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 |