| OLD | NEW |
| 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 "jwk.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <functional> | 8 #include <functional> |
| 9 #include <map> | 9 #include <map> |
| 10 | 10 |
| (...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 Status status = GetJwkString(dict, path, &base64_string); | 315 Status status = GetJwkString(dict, path, &base64_string); |
| 316 if (status.IsError()) | 316 if (status.IsError()) |
| 317 return status; | 317 return status; |
| 318 | 318 |
| 319 if (!Base64DecodeUrlSafe(base64_string, result)) | 319 if (!Base64DecodeUrlSafe(base64_string, result)) |
| 320 return Status::ErrorJwkBase64Decode(path); | 320 return Status::ErrorJwkBase64Decode(path); |
| 321 | 321 |
| 322 return Status::Success(); | 322 return Status::Success(); |
| 323 } | 323 } |
| 324 | 324 |
| 325 // Extracts the optional string property with key |path| from |dict| and saves | 325 // Extracts the required base64url property, which is interpreted as being a |
| 326 // the base64url-decoded bytes to |*result|. If the property exist and is not a | 326 // big-endian unsigned integer. |
| 327 // string, or could not be base64url-decoded, returns an error. In the case | 327 Status GetJwkBigInteger(base::DictionaryValue* dict, |
| 328 // where the property does not exist, |result| is guaranteed to be empty. | 328 const std::string& path, |
| 329 Status GetOptionalJwkBytes(base::DictionaryValue* dict, | 329 std::string* result) { |
| 330 const std::string& path, | 330 Status status = GetJwkBytes(dict, path, result); |
| 331 std::string* result, | |
| 332 bool* property_exists) { | |
| 333 std::string base64_string; | |
| 334 Status status = | |
| 335 GetOptionalJwkString(dict, path, &base64_string, property_exists); | |
| 336 if (status.IsError()) | 331 if (status.IsError()) |
| 337 return status; | 332 return status; |
| 338 | 333 |
| 339 if (!*property_exists) { | 334 if (result->empty()) |
| 340 result->clear(); | 335 return Status::ErrorJwkEmptyBigInteger(path); |
| 341 return Status::Success(); | |
| 342 } | |
| 343 | 336 |
| 344 if (!Base64DecodeUrlSafe(base64_string, result)) | 337 // The JWA spec says that "The octet sequence MUST utilize the minimum number |
| 345 return Status::ErrorJwkBase64Decode(path); | 338 // of octets to represent the value." This means there shouldn't be any |
| 339 // leading zeros. |
| 340 if (result->size() > 1 && (*result)[0] == 0) |
| 341 return Status::ErrorJwkBigIntegerHasLeadingZero(path); |
| 346 | 342 |
| 347 return Status::Success(); | 343 return Status::Success(); |
| 348 } | 344 } |
| 349 | 345 |
| 350 // Extracts the optional boolean property with key |path| from |dict| and saves | 346 // Extracts the optional boolean property with key |path| from |dict| and saves |
| 351 // the result to |*result| if it was found. If the property exists and is not a | 347 // the result to |*result| if it was found. If the property exists and is not a |
| 352 // boolean, returns an error. Otherwise returns success, and sets | 348 // boolean, returns an error. Otherwise returns success, and sets |
| 353 // |*property_exists| if it was found. | 349 // |*property_exists| if it was found. |
| 354 Status GetOptionalJwkBool(base::DictionaryValue* dict, | 350 Status GetOptionalJwkBool(base::DictionaryValue* dict, |
| 355 const std::string& path, | 351 const std::string& path, |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 643 return status; | 639 return status; |
| 644 | 640 |
| 645 if (kty != "RSA") | 641 if (kty != "RSA") |
| 646 return Status::ErrorJwkUnexpectedKty("RSA"); | 642 return Status::ErrorJwkUnexpectedKty("RSA"); |
| 647 | 643 |
| 648 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry | 644 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry |
| 649 // in the JWK, while an RSA private key must have those, plus at least a "d" | 645 // in the JWK, while an RSA private key must have those, plus at least a "d" |
| 650 // (private exponent) entry. | 646 // (private exponent) entry. |
| 651 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18, | 647 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18, |
| 652 // section 6.3. | 648 // section 6.3. |
| 653 status = GetJwkBytes(dict.get(), "n", &result->n); | 649 status = GetJwkBigInteger(dict.get(), "n", &result->n); |
| 654 if (status.IsError()) | 650 if (status.IsError()) |
| 655 return status; | 651 return status; |
| 656 status = GetJwkBytes(dict.get(), "e", &result->e); | 652 status = GetJwkBigInteger(dict.get(), "e", &result->e); |
| 657 if (status.IsError()) | 653 if (status.IsError()) |
| 658 return status; | 654 return status; |
| 659 | 655 |
| 660 result->is_private_key = dict->HasKey("d"); | 656 result->is_private_key = dict->HasKey("d"); |
| 661 if (!result->is_private_key) | 657 if (!result->is_private_key) |
| 662 return Status::Success(); | 658 return Status::Success(); |
| 663 | 659 |
| 664 status = GetJwkBytes(dict.get(), "d", &result->d); | 660 status = GetJwkBigInteger(dict.get(), "d", &result->d); |
| 665 if (status.IsError()) | 661 if (status.IsError()) |
| 666 return status; | 662 return status; |
| 667 | 663 |
| 668 // The "p", "q", "dp", "dq", and "qi" properties are optional. Treat these | 664 // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA |
| 669 // properties the same if they are unspecified, as if they were specified-but | 665 // spec. However they are required by Chromium's WebCrypto implementation. |
| 670 // empty, since ImportRsaPrivateKey() doesn't do validation checks anyway. | |
| 671 | 666 |
| 672 bool has_p; | 667 status = GetJwkBigInteger(dict.get(), "p", &result->p); |
| 673 status = GetOptionalJwkBytes(dict.get(), "p", &result->p, &has_p); | |
| 674 if (status.IsError()) | 668 if (status.IsError()) |
| 675 return status; | 669 return status; |
| 676 | 670 |
| 677 bool has_q; | 671 status = GetJwkBigInteger(dict.get(), "q", &result->q); |
| 678 status = GetOptionalJwkBytes(dict.get(), "q", &result->q, &has_q); | |
| 679 if (status.IsError()) | 672 if (status.IsError()) |
| 680 return status; | 673 return status; |
| 681 | 674 |
| 682 bool has_dp; | 675 status = GetJwkBigInteger(dict.get(), "dp", &result->dp); |
| 683 status = GetOptionalJwkBytes(dict.get(), "dp", &result->dp, &has_dp); | |
| 684 if (status.IsError()) | 676 if (status.IsError()) |
| 685 return status; | 677 return status; |
| 686 | 678 |
| 687 bool has_dq; | 679 status = GetJwkBigInteger(dict.get(), "dq", &result->dq); |
| 688 status = GetOptionalJwkBytes(dict.get(), "dq", &result->dq, &has_dq); | |
| 689 if (status.IsError()) | 680 if (status.IsError()) |
| 690 return status; | 681 return status; |
| 691 | 682 |
| 692 bool has_qi; | 683 status = GetJwkBigInteger(dict.get(), "qi", &result->qi); |
| 693 status = GetOptionalJwkBytes(dict.get(), "qi", &result->qi, &has_qi); | |
| 694 if (status.IsError()) | 684 if (status.IsError()) |
| 695 return status; | 685 return status; |
| 696 | 686 |
| 697 int num_optional_properties = has_p + has_q + has_dp + has_dq + has_qi; | |
| 698 if (num_optional_properties != 0 && num_optional_properties != 5) | |
| 699 return Status::ErrorJwkIncompleteOptionalRsaPrivateKey(); | |
| 700 | |
| 701 return Status::Success(); | 687 return Status::Success(); |
| 702 } | 688 } |
| 703 | 689 |
| 704 const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) { | 690 const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) { |
| 705 switch (hash) { | 691 switch (hash) { |
| 706 case blink::WebCryptoAlgorithmIdSha1: | 692 case blink::WebCryptoAlgorithmIdSha1: |
| 707 return "HS1"; | 693 return "HS1"; |
| 708 case blink::WebCryptoAlgorithmIdSha256: | 694 case blink::WebCryptoAlgorithmIdSha256: |
| 709 return "HS256"; | 695 return "HS256"; |
| 710 case blink::WebCryptoAlgorithmIdSha384: | 696 case blink::WebCryptoAlgorithmIdSha384: |
| 711 return "HS384"; | 697 return "HS384"; |
| 712 case blink::WebCryptoAlgorithmIdSha512: | 698 case blink::WebCryptoAlgorithmIdSha512: |
| 713 return "HS512"; | 699 return "HS512"; |
| 714 default: | 700 default: |
| 715 return NULL; | 701 return NULL; |
| 716 } | 702 } |
| 717 } | 703 } |
| 718 | 704 |
| 719 } // namespace webcrypto | 705 } // namespace webcrypto |
| 720 | 706 |
| 721 } // namespace content | 707 } // namespace content |
| OLD | NEW |