Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Side by Side Diff: content/child/webcrypto/jwk.cc

Issue 687063002: Refactor: Expose JwkReader/JwkWriter helper classes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: utf-8 --> UTF-8 Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« content/child/webcrypto/jwk.h ('K') | « content/child/webcrypto/jwk.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "jwk.h" 5 #include "content/child/webcrypto/jwk.h"
6
7 #include <algorithm>
8 #include <functional>
9 #include <map>
10 6
11 #include "base/base64.h" 7 #include "base/base64.h"
12 #include "base/json/json_reader.h" 8 #include "base/json/json_reader.h"
13 #include "base/json/json_writer.h" 9 #include "base/json/json_writer.h"
14 #include "base/stl_util.h" 10 #include "base/stl_util.h"
15 #include "base/strings/string_piece.h" 11 #include "base/strings/string_piece.h"
16 #include "content/child/webcrypto/crypto_data.h" 12 #include "content/child/webcrypto/crypto_data.h"
17 #include "content/child/webcrypto/status.h" 13 #include "content/child/webcrypto/status.h"
18 #include "content/child/webcrypto/webcrypto_util.h" 14 #include "content/child/webcrypto/webcrypto_util.h"
19 15
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 209
214 // Web Crypto equivalent usage mask for JWK 'use' = 'enc'. 210 // Web Crypto equivalent usage mask for JWK 'use' = 'enc'.
215 const blink::WebCryptoKeyUsageMask kJwkEncUsage = 211 const blink::WebCryptoKeyUsageMask kJwkEncUsage =
216 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt | 212 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
217 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey | 213 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey |
218 blink::WebCryptoKeyUsageDeriveKey | blink::WebCryptoKeyUsageDeriveBits; 214 blink::WebCryptoKeyUsageDeriveKey | blink::WebCryptoKeyUsageDeriveBits;
219 // Web Crypto equivalent usage mask for JWK 'use' = 'sig'. 215 // Web Crypto equivalent usage mask for JWK 'use' = 'sig'.
220 const blink::WebCryptoKeyUsageMask kJwkSigUsage = 216 const blink::WebCryptoKeyUsageMask kJwkSigUsage =
221 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; 217 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
222 218
223 class JwkWriter { 219 // Checks that the "ext" member of the JWK is consistent with
224 public: 220 // "expected_extractable".
225 JwkWriter(const std::string& algorithm, 221 Status VerifyExt(const JwkReader& jwk, bool expected_extractable) {
226 bool extractable,
227 blink::WebCryptoKeyUsageMask usages,
228 const std::string& kty) {
229 dict_.SetString("alg", algorithm);
230 dict_.Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(usages));
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 222 // JWK "ext" (optional) --> extractable parameter
370 bool jwk_ext_value = false; 223 bool jwk_ext_value = false;
371 bool has_jwk_ext; 224 bool has_jwk_ext;
372 Status status = GetOptionalJwkBool(dict, "ext", &jwk_ext_value, &has_jwk_ext); 225 Status status = jwk.GetOptionalBool("ext", &jwk_ext_value, &has_jwk_ext);
373 if (status.IsError()) 226 if (status.IsError())
374 return status; 227 return status;
375 if (has_jwk_ext && expected_extractable && !jwk_ext_value) 228 if (has_jwk_ext && expected_extractable && !jwk_ext_value)
376 return Status::ErrorJwkExtInconsistent(); 229 return Status::ErrorJwkExtInconsistent();
377 return Status::Success(); 230 return Status::Success();
378 } 231 }
379 232
380 Status VerifyUsages(base::DictionaryValue* dict, 233 // Checks that the usages ("use" and "key_ops") of the JWK is consistent with
234 // "expected_usages".
235 Status VerifyUsages(const JwkReader& jwk,
381 blink::WebCryptoKeyUsageMask expected_usages) { 236 blink::WebCryptoKeyUsageMask expected_usages) {
382 // JWK "key_ops" (optional) --> usages parameter 237 // JWK "key_ops" (optional) --> usages parameter
383 base::ListValue* jwk_key_ops_value = NULL; 238 base::ListValue* jwk_key_ops_value = NULL;
384 bool has_jwk_key_ops; 239 bool has_jwk_key_ops;
385 Status status = 240 Status status =
386 GetOptionalJwkList(dict, "key_ops", &jwk_key_ops_value, &has_jwk_key_ops); 241 jwk.GetOptionalList("key_ops", &jwk_key_ops_value, &has_jwk_key_ops);
387 if (status.IsError()) 242 if (status.IsError())
388 return status; 243 return status;
389 blink::WebCryptoKeyUsageMask jwk_key_ops_mask = 0; 244 blink::WebCryptoKeyUsageMask jwk_key_ops_mask = 0;
390 if (has_jwk_key_ops) { 245 if (has_jwk_key_ops) {
391 status = 246 status =
392 GetWebCryptoUsagesFromJwkKeyOps(jwk_key_ops_value, &jwk_key_ops_mask); 247 GetWebCryptoUsagesFromJwkKeyOps(jwk_key_ops_value, &jwk_key_ops_mask);
393 if (status.IsError()) 248 if (status.IsError())
394 return status; 249 return status;
395 // The input usages must be a subset of jwk_key_ops_mask. 250 // The input usages must be a subset of jwk_key_ops_mask.
396 if (!ContainsKeyUsages(jwk_key_ops_mask, expected_usages)) 251 if (!ContainsKeyUsages(jwk_key_ops_mask, expected_usages))
397 return Status::ErrorJwkKeyopsInconsistent(); 252 return Status::ErrorJwkKeyopsInconsistent();
398 } 253 }
399 254
400 // JWK "use" (optional) --> usages parameter 255 // JWK "use" (optional) --> usages parameter
401 std::string jwk_use_value; 256 std::string jwk_use_value;
402 bool has_jwk_use; 257 bool has_jwk_use;
403 status = GetOptionalJwkString(dict, "use", &jwk_use_value, &has_jwk_use); 258 status = jwk.GetOptionalString("use", &jwk_use_value, &has_jwk_use);
404 if (status.IsError()) 259 if (status.IsError())
405 return status; 260 return status;
406 blink::WebCryptoKeyUsageMask jwk_use_mask = 0; 261 blink::WebCryptoKeyUsageMask jwk_use_mask = 0;
407 if (has_jwk_use) { 262 if (has_jwk_use) {
408 if (jwk_use_value == "enc") 263 if (jwk_use_value == "enc")
409 jwk_use_mask = kJwkEncUsage; 264 jwk_use_mask = kJwkEncUsage;
410 else if (jwk_use_value == "sig") 265 else if (jwk_use_value == "sig")
411 jwk_use_mask = kJwkSigUsage; 266 jwk_use_mask = kJwkSigUsage;
412 else 267 else
413 return Status::ErrorJwkUnrecognizedUse(); 268 return Status::ErrorJwkUnrecognizedUse();
414 // The input usages must be a subset of jwk_use_mask. 269 // The input usages must be a subset of jwk_use_mask.
415 if (!ContainsKeyUsages(jwk_use_mask, expected_usages)) 270 if (!ContainsKeyUsages(jwk_use_mask, expected_usages))
416 return Status::ErrorJwkUseInconsistent(); 271 return Status::ErrorJwkUseInconsistent();
417 } 272 }
418 273
419 // If both 'key_ops' and 'use' are present, ensure they are consistent. 274 // If both 'key_ops' and 'use' are present, ensure they are consistent.
420 if (has_jwk_key_ops && has_jwk_use && 275 if (has_jwk_key_ops && has_jwk_use &&
421 !ContainsKeyUsages(jwk_use_mask, jwk_key_ops_mask)) 276 !ContainsKeyUsages(jwk_use_mask, jwk_key_ops_mask))
422 return Status::ErrorJwkUseAndKeyopsInconsistent(); 277 return Status::ErrorJwkUseAndKeyopsInconsistent();
423 278
424 return Status::Success(); 279 return Status::Success();
425 } 280 }
426 281
427 Status VerifyAlg(base::DictionaryValue* dict, 282 } // namespace
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 283
437 if (has_jwk_alg && jwk_alg_value != expected_algorithm) 284 JwkReader::JwkReader() {
438 return Status::ErrorJwkAlgorithmInconsistent();
439
440 return Status::Success();
441 } 285 }
442 286
443 Status ParseJwkCommon(const CryptoData& bytes, 287 JwkReader::~JwkReader() {
444 bool expected_extractable, 288 }
445 blink::WebCryptoKeyUsageMask expected_usages, 289
446 std::string* kty, 290 Status JwkReader::Init(const CryptoData& bytes,
447 scoped_ptr<base::DictionaryValue>* dict) { 291 bool expected_extractable,
292 blink::WebCryptoKeyUsageMask expected_usages,
293 const std::string& expected_kty,
294 const std::string& expected_alg) {
295 if (!bytes.byte_length())
296 return Status::ErrorImportEmptyKeyData();
297
448 // Parse the incoming JWK JSON. 298 // Parse the incoming JWK JSON.
449 base::StringPiece json_string(reinterpret_cast<const char*>(bytes.bytes()), 299 base::StringPiece json_string(reinterpret_cast<const char*>(bytes.bytes()),
450 bytes.byte_length()); 300 bytes.byte_length());
451 301
452 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string)); 302 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
453 base::DictionaryValue* dict_value = NULL; 303 base::DictionaryValue* dict_value = NULL;
454 304
455 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value) 305 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value)
456 return Status::ErrorJwkNotDictionary(); 306 return Status::ErrorJwkNotDictionary();
457 307
458 // Release |value|, as ownership will be transferred to |dict| via 308 // Release |value|, as ownership will be transferred to |dict| via
459 // |dict_value|, which points to the same object as |value|. 309 // |dict_value|, which points to the same object as |value|.
460 ignore_result(value.release()); 310 ignore_result(value.release());
461 dict->reset(dict_value); 311 dict_.reset(dict_value);
462 312
463 // JWK "kty". Exit early if this required JWK parameter is missing. 313 // JWK "kty". Exit early if this required JWK parameter is missing.
464 Status status = GetJwkString(dict_value, "kty", kty); 314 std::string kty;
315 Status status = GetString("kty", &kty);
465 if (status.IsError()) 316 if (status.IsError())
466 return status; 317 return status;
467 318
468 status = VerifyExt(dict_value, expected_extractable); 319 if (kty != expected_kty)
320 return Status::ErrorJwkUnexpectedKty(expected_kty);
321
322 status = VerifyExt(*this, expected_extractable);
469 if (status.IsError()) 323 if (status.IsError())
470 return status; 324 return status;
471 325
472 status = VerifyUsages(dict_value, expected_usages); 326 status = VerifyUsages(*this, expected_usages);
473 if (status.IsError()) 327 if (status.IsError())
474 return status; 328 return status;
475 329
330 // Verify the algorithm if an expectation was provided.
331 if (!expected_alg.empty()) {
332 status = VerifyAlg(expected_alg);
333 if (status.IsError())
334 return status;
335 }
336
476 return Status::Success(); 337 return Status::Success();
477 } 338 }
478 339
340 bool JwkReader::HasMember(const std::string& member_name) const {
341 return dict_->HasKey(member_name);
342 }
343
344 Status JwkReader::GetString(const std::string& member_name,
345 std::string* result) const {
346 base::Value* value = NULL;
347 if (!dict_->Get(member_name, &value))
348 return Status::ErrorJwkPropertyMissing(member_name);
349 if (!value->GetAsString(result))
350 return Status::ErrorJwkPropertyWrongType(member_name, "string");
351 return Status::Success();
352 }
353
354 Status JwkReader::GetOptionalString(const std::string& member_name,
355 std::string* result,
356 bool* member_exists) const {
357 *member_exists = false;
358 base::Value* value = NULL;
359 if (!dict_->Get(member_name, &value))
360 return Status::Success();
361
362 if (!value->GetAsString(result))
363 return Status::ErrorJwkPropertyWrongType(member_name, "string");
364
365 *member_exists = true;
366 return Status::Success();
367 }
368
369 Status JwkReader::GetOptionalList(const std::string& member_name,
370 base::ListValue** result,
371 bool* member_exists) const {
372 *member_exists = false;
373 base::Value* value = NULL;
374 if (!dict_->Get(member_name, &value))
375 return Status::Success();
376
377 if (!value->GetAsList(result))
378 return Status::ErrorJwkPropertyWrongType(member_name, "list");
379
380 *member_exists = true;
381 return Status::Success();
382 }
383
384 Status JwkReader::GetBytes(const std::string& member_name,
385 std::string* result) const {
386 std::string base64_string;
387 Status status = GetString(member_name, &base64_string);
388 if (status.IsError())
389 return status;
390
391 if (!Base64DecodeUrlSafe(base64_string, result))
392 return Status::ErrorJwkBase64Decode(member_name);
393
394 return Status::Success();
395 }
396
397 Status JwkReader::GetBigInteger(const std::string& member_name,
398 std::string* result) const {
399 Status status = GetBytes(member_name, result);
400 if (status.IsError())
401 return status;
402
403 if (result->empty())
404 return Status::ErrorJwkEmptyBigInteger(member_name);
405
406 // The JWA spec says that "The octet sequence MUST utilize the minimum number
407 // of octets to represent the value." This means there shouldn't be any
408 // leading zeros.
409 if (result->size() > 1 && (*result)[0] == 0)
410 return Status::ErrorJwkBigIntegerHasLeadingZero(member_name);
411
412 return Status::Success();
413 }
414
415 Status JwkReader::GetOptionalBool(const std::string& member_name,
416 bool* result,
417 bool* member_exists) const {
418 *member_exists = false;
419 base::Value* value = NULL;
420 if (!dict_->Get(member_name, &value))
421 return Status::Success();
422
423 if (!value->GetAsBoolean(result))
424 return Status::ErrorJwkPropertyWrongType(member_name, "boolean");
425
426 *member_exists = true;
427 return Status::Success();
428 }
429
430 Status JwkReader::GetAlg(std::string* alg, bool* has_alg) const {
431 return GetOptionalString("alg", alg, has_alg);
432 }
433
434 Status JwkReader::VerifyAlg(const std::string& expected_alg) const {
435 bool has_jwk_alg;
436 std::string jwk_alg_value;
437 Status status = GetAlg(&jwk_alg_value, &has_jwk_alg);
438 if (status.IsError())
439 return status;
440
441 if (has_jwk_alg && jwk_alg_value != expected_alg)
442 return Status::ErrorJwkAlgorithmInconsistent();
443
444 return Status::Success();
445 }
446
447 JwkWriter::JwkWriter(const std::string& algorithm,
448 bool extractable,
449 blink::WebCryptoKeyUsageMask usages,
450 const std::string& kty) {
451 dict_.SetString("alg", algorithm);
452 dict_.Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(usages));
453 dict_.SetBoolean("ext", extractable);
454 dict_.SetString("kty", kty);
455 }
456
457 void JwkWriter::SetString(const std::string& member_name,
458 const std::string& value) {
459 dict_.SetString(member_name, value);
460 }
461
462 void JwkWriter::SetBytes(const std::string& member_name,
463 const CryptoData& value) {
464 dict_.SetString(
465 member_name,
466 Base64EncodeUrlSafe(base::StringPiece(
467 reinterpret_cast<const char*>(value.bytes()), value.byte_length())));
468 }
469
470 void JwkWriter::ToJson(std::vector<uint8_t>* utf8_bytes) const {
471 std::string json;
472 base::JSONWriter::Write(&dict_, &json);
473 utf8_bytes->assign(json.begin(), json.end());
474 }
475
479 Status ReadSecretKeyNoExpectedAlg(const CryptoData& key_data, 476 Status ReadSecretKeyNoExpectedAlg(const CryptoData& key_data,
480 bool expected_extractable, 477 bool expected_extractable,
481 blink::WebCryptoKeyUsageMask expected_usages, 478 blink::WebCryptoKeyUsageMask expected_usages,
482 std::vector<uint8_t>* raw_key_data, 479 std::vector<uint8_t>* raw_key_data,
483 scoped_ptr<base::DictionaryValue>* dict) { 480 JwkReader* jwk) {
484 if (!key_data.byte_length()) 481 Status status = jwk->Init(
485 return Status::ErrorImportEmptyKeyData(); 482 key_data, expected_extractable, expected_usages, "oct", std::string());
486
487 std::string kty;
488 Status status = ParseJwkCommon(
489 key_data, expected_extractable, expected_usages, &kty, dict);
490 if (status.IsError()) 483 if (status.IsError())
491 return status; 484 return status;
492 485
493 if (kty != "oct")
494 return Status::ErrorJwkUnexpectedKty("oct");
495
496 std::string jwk_k_value; 486 std::string jwk_k_value;
497 status = GetJwkBytes(dict->get(), "k", &jwk_k_value); 487 status = jwk->GetBytes("k", &jwk_k_value);
498 if (status.IsError()) 488 if (status.IsError())
499 return status; 489 return status;
500 raw_key_data->assign(jwk_k_value.begin(), jwk_k_value.end()); 490 raw_key_data->assign(jwk_k_value.begin(), jwk_k_value.end());
501 491
502 return Status::Success(); 492 return Status::Success();
503 } 493 }
504 494
505 } // namespace
506
507 void WriteSecretKeyJwk(const CryptoData& raw_key_data, 495 void WriteSecretKeyJwk(const CryptoData& raw_key_data,
508 const std::string& algorithm, 496 const std::string& algorithm,
509 bool extractable, 497 bool extractable,
510 blink::WebCryptoKeyUsageMask usages, 498 blink::WebCryptoKeyUsageMask usages,
511 std::vector<uint8_t>* jwk_key_data) { 499 std::vector<uint8_t>* jwk_key_data) {
512 JwkWriter writer(algorithm, extractable, usages, "oct"); 500 JwkWriter writer(algorithm, extractable, usages, "oct");
513 writer.SetBase64Encoded("k", raw_key_data); 501 writer.SetBytes("k", raw_key_data);
514 writer.ToBytes(jwk_key_data); 502 writer.ToJson(jwk_key_data);
515 } 503 }
516 504
517 Status ReadSecretKeyJwk(const CryptoData& key_data, 505 Status ReadSecretKeyJwk(const CryptoData& key_data,
518 const std::string& expected_algorithm, 506 const std::string& expected_alg,
519 bool expected_extractable, 507 bool expected_extractable,
520 blink::WebCryptoKeyUsageMask expected_usages, 508 blink::WebCryptoKeyUsageMask expected_usages,
521 std::vector<uint8_t>* raw_key_data) { 509 std::vector<uint8_t>* raw_key_data) {
522 scoped_ptr<base::DictionaryValue> dict; 510 JwkReader jwk;
523 Status status = ReadSecretKeyNoExpectedAlg( 511 Status status = ReadSecretKeyNoExpectedAlg(
524 key_data, expected_extractable, expected_usages, raw_key_data, &dict); 512 key_data, expected_extractable, expected_usages, raw_key_data, &jwk);
525 if (status.IsError()) 513 if (status.IsError())
526 return status; 514 return status;
527 return VerifyAlg(dict.get(), expected_algorithm); 515 return jwk.VerifyAlg(expected_alg);
528 } 516 }
529 517
530 std::string MakeJwkAesAlgorithmName(const std::string& suffix, 518 std::string MakeJwkAesAlgorithmName(const std::string& suffix,
531 unsigned int keylen_bytes) { 519 unsigned int keylen_bytes) {
532 if (keylen_bytes == 16) 520 if (keylen_bytes == 16)
533 return std::string("A128") + suffix; 521 return std::string("A128") + suffix;
534 if (keylen_bytes == 24) 522 if (keylen_bytes == 24)
535 return std::string("A192") + suffix; 523 return std::string("A192") + suffix;
536 if (keylen_bytes == 32) 524 if (keylen_bytes == 32)
537 return std::string("A256") + suffix; 525 return std::string("A256") + suffix;
538 return std::string(); 526 return std::string();
539 } 527 }
540 528
541 Status ReadAesSecretKeyJwk(const CryptoData& key_data, 529 Status ReadAesSecretKeyJwk(const CryptoData& key_data,
542 const std::string& algorithm_name_suffix, 530 const std::string& algorithm_name_suffix,
543 bool expected_extractable, 531 bool expected_extractable,
544 blink::WebCryptoKeyUsageMask expected_usages, 532 blink::WebCryptoKeyUsageMask expected_usages,
545 std::vector<uint8_t>* raw_key_data) { 533 std::vector<uint8_t>* raw_key_data) {
546 scoped_ptr<base::DictionaryValue> dict; 534 JwkReader jwk;
547 Status status = ReadSecretKeyNoExpectedAlg( 535 Status status = ReadSecretKeyNoExpectedAlg(
548 key_data, expected_extractable, expected_usages, raw_key_data, &dict); 536 key_data, expected_extractable, expected_usages, raw_key_data, &jwk);
549 if (status.IsError()) 537 if (status.IsError())
550 return status; 538 return status;
551 539
552 bool has_jwk_alg; 540 bool has_jwk_alg;
553 std::string jwk_alg; 541 std::string jwk_alg;
554 status = GetOptionalJwkString(dict.get(), "alg", &jwk_alg, &has_jwk_alg); 542 status = jwk.GetAlg(&jwk_alg, &has_jwk_alg);
555 if (status.IsError()) 543 if (status.IsError())
556 return status; 544 return status;
557 545
558 if (has_jwk_alg) { 546 if (has_jwk_alg) {
559 std::string expected_algorithm_name = 547 std::string expected_algorithm_name =
560 MakeJwkAesAlgorithmName(algorithm_name_suffix, raw_key_data->size()); 548 MakeJwkAesAlgorithmName(algorithm_name_suffix, raw_key_data->size());
561 549
562 if (jwk_alg != expected_algorithm_name) { 550 if (jwk_alg != expected_algorithm_name) {
563 // Give a different error message if the key length was wrong. 551 // Give a different error message if the key length was wrong.
564 if (jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 16) || 552 if (jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 16) ||
565 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 24) || 553 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 24) ||
566 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 32)) { 554 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 32)) {
567 return Status::ErrorJwkIncorrectKeyLength(); 555 return Status::ErrorJwkIncorrectKeyLength();
568 } 556 }
569 return Status::ErrorJwkAlgorithmInconsistent(); 557 return Status::ErrorJwkAlgorithmInconsistent();
570 } 558 }
571 } 559 }
572 560
573 return Status::Success(); 561 return Status::Success();
574 } 562 }
575 563
576 // Writes an RSA public key to a JWK dictionary 564 // Writes an RSA public key to a JWK dictionary
577 void WriteRsaPublicKeyJwk(const CryptoData& n, 565 void WriteRsaPublicKeyJwk(const CryptoData& n,
578 const CryptoData& e, 566 const CryptoData& e,
579 const std::string& algorithm, 567 const std::string& algorithm,
580 bool extractable, 568 bool extractable,
581 blink::WebCryptoKeyUsageMask usages, 569 blink::WebCryptoKeyUsageMask usages,
582 std::vector<uint8_t>* jwk_key_data) { 570 std::vector<uint8_t>* jwk_key_data) {
583 JwkWriter writer(algorithm, extractable, usages, "RSA"); 571 JwkWriter writer(algorithm, extractable, usages, "RSA");
584 writer.SetBase64Encoded("n", n); 572 writer.SetBytes("n", n);
585 writer.SetBase64Encoded("e", e); 573 writer.SetBytes("e", e);
586 writer.ToBytes(jwk_key_data); 574 writer.ToJson(jwk_key_data);
587 } 575 }
588 576
589 // Writes an RSA private key to a JWK dictionary 577 // Writes an RSA private key to a JWK dictionary
590 void WriteRsaPrivateKeyJwk(const CryptoData& n, 578 void WriteRsaPrivateKeyJwk(const CryptoData& n,
591 const CryptoData& e, 579 const CryptoData& e,
592 const CryptoData& d, 580 const CryptoData& d,
593 const CryptoData& p, 581 const CryptoData& p,
594 const CryptoData& q, 582 const CryptoData& q,
595 const CryptoData& dp, 583 const CryptoData& dp,
596 const CryptoData& dq, 584 const CryptoData& dq,
597 const CryptoData& qi, 585 const CryptoData& qi,
598 const std::string& algorithm, 586 const std::string& algorithm,
599 bool extractable, 587 bool extractable,
600 blink::WebCryptoKeyUsageMask usages, 588 blink::WebCryptoKeyUsageMask usages,
601 std::vector<uint8_t>* jwk_key_data) { 589 std::vector<uint8_t>* jwk_key_data) {
602 JwkWriter writer(algorithm, extractable, usages, "RSA"); 590 JwkWriter writer(algorithm, extractable, usages, "RSA");
603 591
604 writer.SetBase64Encoded("n", n); 592 writer.SetBytes("n", n);
605 writer.SetBase64Encoded("e", e); 593 writer.SetBytes("e", e);
606 writer.SetBase64Encoded("d", d); 594 writer.SetBytes("d", d);
607 // Although these are "optional" in the JWA, WebCrypto spec requires them to 595 // Although these are "optional" in the JWA, WebCrypto spec requires them to
608 // be emitted. 596 // be emitted.
609 writer.SetBase64Encoded("p", p); 597 writer.SetBytes("p", p);
610 writer.SetBase64Encoded("q", q); 598 writer.SetBytes("q", q);
611 writer.SetBase64Encoded("dp", dp); 599 writer.SetBytes("dp", dp);
612 writer.SetBase64Encoded("dq", dq); 600 writer.SetBytes("dq", dq);
613 writer.SetBase64Encoded("qi", qi); 601 writer.SetBytes("qi", qi);
614 writer.ToBytes(jwk_key_data); 602 writer.ToJson(jwk_key_data);
615 } 603 }
616 604
617 JwkRsaInfo::JwkRsaInfo() : is_private_key(false) { 605 JwkRsaInfo::JwkRsaInfo() : is_private_key(false) {
618 } 606 }
619 607
620 JwkRsaInfo::~JwkRsaInfo() { 608 JwkRsaInfo::~JwkRsaInfo() {
621 } 609 }
622 610
623 Status ReadRsaKeyJwk(const CryptoData& key_data, 611 Status ReadRsaKeyJwk(const CryptoData& key_data,
624 const std::string& expected_algorithm, 612 const std::string& expected_alg,
625 bool expected_extractable, 613 bool expected_extractable,
626 blink::WebCryptoKeyUsageMask expected_usages, 614 blink::WebCryptoKeyUsageMask expected_usages,
627 JwkRsaInfo* result) { 615 JwkRsaInfo* result) {
628 if (!key_data.byte_length()) 616 JwkReader jwk;
629 return Status::ErrorImportEmptyKeyData(); 617 Status status = jwk.Init(
630 618 key_data, expected_extractable, expected_usages, "RSA", expected_alg);
631 scoped_ptr<base::DictionaryValue> dict;
632 std::string kty;
633 Status status = ParseJwkCommon(
634 key_data, expected_extractable, expected_usages, &kty, &dict);
635 if (status.IsError()) 619 if (status.IsError())
636 return status; 620 return status;
637 621
638 status = VerifyAlg(dict.get(), expected_algorithm);
639 if (status.IsError())
640 return status;
641
642 if (kty != "RSA")
643 return Status::ErrorJwkUnexpectedKty("RSA");
644
645 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry 622 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
646 // in the JWK, while an RSA private key must have those, plus at least a "d" 623 // in the JWK, while an RSA private key must have those, plus at least a "d"
647 // (private exponent) entry. 624 // (private exponent) entry.
648 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18, 625 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
649 // section 6.3. 626 // section 6.3.
650 status = GetJwkBigInteger(dict.get(), "n", &result->n); 627 status = jwk.GetBigInteger("n", &result->n);
651 if (status.IsError()) 628 if (status.IsError())
652 return status; 629 return status;
653 status = GetJwkBigInteger(dict.get(), "e", &result->e); 630 status = jwk.GetBigInteger("e", &result->e);
654 if (status.IsError()) 631 if (status.IsError())
655 return status; 632 return status;
656 633
657 result->is_private_key = dict->HasKey("d"); 634 result->is_private_key = jwk.HasMember("d");
658 if (!result->is_private_key) 635 if (!result->is_private_key)
659 return Status::Success(); 636 return Status::Success();
660 637
661 status = GetJwkBigInteger(dict.get(), "d", &result->d); 638 status = jwk.GetBigInteger("d", &result->d);
662 if (status.IsError()) 639 if (status.IsError())
663 return status; 640 return status;
664 641
665 // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA 642 // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA
666 // spec. However they are required by Chromium's WebCrypto implementation. 643 // spec. However they are required by Chromium's WebCrypto implementation.
667 644
668 status = GetJwkBigInteger(dict.get(), "p", &result->p); 645 status = jwk.GetBigInteger("p", &result->p);
669 if (status.IsError()) 646 if (status.IsError())
670 return status; 647 return status;
671 648
672 status = GetJwkBigInteger(dict.get(), "q", &result->q); 649 status = jwk.GetBigInteger("q", &result->q);
673 if (status.IsError()) 650 if (status.IsError())
674 return status; 651 return status;
675 652
676 status = GetJwkBigInteger(dict.get(), "dp", &result->dp); 653 status = jwk.GetBigInteger("dp", &result->dp);
677 if (status.IsError()) 654 if (status.IsError())
678 return status; 655 return status;
679 656
680 status = GetJwkBigInteger(dict.get(), "dq", &result->dq); 657 status = jwk.GetBigInteger("dq", &result->dq);
681 if (status.IsError()) 658 if (status.IsError())
682 return status; 659 return status;
683 660
684 status = GetJwkBigInteger(dict.get(), "qi", &result->qi); 661 status = jwk.GetBigInteger("qi", &result->qi);
685 if (status.IsError()) 662 if (status.IsError())
686 return status; 663 return status;
687 664
688 return Status::Success(); 665 return Status::Success();
689 } 666 }
690 667
691 const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) { 668 const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) {
692 switch (hash) { 669 switch (hash) {
693 case blink::WebCryptoAlgorithmIdSha1: 670 case blink::WebCryptoAlgorithmIdSha1:
694 return "HS1"; 671 return "HS1";
(...skipping 30 matching lines...) Expand all
725 702
726 std::string Base64EncodeUrlSafe(const std::vector<uint8_t>& input) { 703 std::string Base64EncodeUrlSafe(const std::vector<uint8_t>& input) {
727 const base::StringPiece string_piece( 704 const base::StringPiece string_piece(
728 reinterpret_cast<const char*>(vector_as_array(&input)), input.size()); 705 reinterpret_cast<const char*>(vector_as_array(&input)), input.size());
729 return Base64EncodeUrlSafe(string_piece); 706 return Base64EncodeUrlSafe(string_piece);
730 } 707 }
731 708
732 } // namespace webcrypto 709 } // namespace webcrypto
733 710
734 } // namespace content 711 } // namespace content
OLDNEW
« content/child/webcrypto/jwk.h ('K') | « content/child/webcrypto/jwk.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698