Chromium Code Reviews| 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 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 123 // | "A192GCM" | AES GCM using 192 bit keys | | 123 // | "A192GCM" | AES GCM using 192 bit keys | |
| 124 // | "A256GCM" | AES GCM using 256 bit keys | | 124 // | "A256GCM" | AES GCM using 256 bit keys | |
| 125 // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 | | 125 // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 | |
| 126 // | | padding [NIST.800-38A] | | 126 // | | padding [NIST.800-38A] | |
| 127 // | "A192CBC" | AES CBC using 192 bit keys | | 127 // | "A192CBC" | AES CBC using 192 bit keys | |
| 128 // | "A256CBC" | AES CBC using 256 bit keys | | 128 // | "A256CBC" | AES CBC using 256 bit keys | |
| 129 // +--------------+-------------------------------------------------------+ | 129 // +--------------+-------------------------------------------------------+ |
| 130 // | 130 // |
| 131 // kty-specific parameters | 131 // kty-specific parameters |
| 132 // The value of kty determines the type and content of the keying material | 132 // The value of kty determines the type and content of the keying material |
| 133 // carried in the JWK to be imported. Currently only two possibilities are | 133 // carried in the JWK to be imported. |
| 134 // supported: a raw key or an RSA public key. RSA private keys are not | 134 // // - kty == "oct" (symmetric or other raw key) |
| 135 // supported because typical applications seldom need to import a private key, | |
| 136 // and the large number of JWK parameters required to describe one. | |
| 137 // - kty == "oct" (symmetric or other raw key) | |
| 138 // +-------+--------------------------------------------------------------+ | 135 // +-------+--------------------------------------------------------------+ |
| 139 // | "k" | Contains the value of the symmetric (or other single-valued) | | 136 // | "k" | Contains the value of the symmetric (or other single-valued) | |
| 140 // | | key. It is represented as the base64url encoding of the | | 137 // | | key. It is represented as the base64url encoding of the | |
| 141 // | | octet sequence containing the key value. | | 138 // | | octet sequence containing the key value. | |
| 142 // +-------+--------------------------------------------------------------+ | 139 // +-------+--------------------------------------------------------------+ |
| 143 // - kty == "RSA" (RSA public key) | 140 // - kty == "RSA" (RSA public key) |
| 144 // +-------+--------------------------------------------------------------+ | 141 // +-------+--------------------------------------------------------------+ |
| 145 // | "n" | Contains the modulus value for the RSA public key. It is | | 142 // | "n" | Contains the modulus value for the RSA public key. It is | |
| 146 // | | represented as the base64url encoding of the value's | | 143 // | | represented as the base64url encoding of the value's | |
| 147 // | | unsigned big endian representation as an octet sequence. | | 144 // | | unsigned big endian representation as an octet sequence. | |
| 148 // +-------+--------------------------------------------------------------+ | 145 // +-------+--------------------------------------------------------------+ |
| 149 // | "e" | Contains the exponent value for the RSA public key. It is | | 146 // | "e" | Contains the exponent value for the RSA public key. It is | |
| 150 // | | represented as the base64url encoding of the value's | | 147 // | | represented as the base64url encoding of the value's | |
| 151 // | | unsigned big endian representation as an octet sequence. | | 148 // | | unsigned big endian representation as an octet sequence. | |
| 152 // +-------+--------------------------------------------------------------+ | 149 // +-------+--------------------------------------------------------------+ |
| 150 // - If key == "RSA" and the "d" parameter is present then it is a private key. | |
| 151 // All the parameters above for public keys apply, as well as the following. | |
| 152 // (Note that except for "d", all of these are optional): | |
| 153 // +-------+--------------------------------------------------------------+ | |
| 154 // | "d" | Contains the private exponent value for the RSA private key. | | |
| 155 // | | It is represented as the base64url encoding of the value's | | |
| 156 // | | unsigned big endian representation as an octet sequence. | | |
| 157 // +-------+--------------------------------------------------------------+ | |
| 158 // | "p" | Contains the first prime factor value for the RSA private | | |
| 159 // | | key. It is represented as the base64url encoding of the | | |
| 160 // | | value's | | |
| 161 // | | unsigned big endian representation as an octet sequence. | | |
| 162 // +-------+--------------------------------------------------------------+ | |
| 163 // | "q" | Contains the second prime factor value for the RSA private | | |
| 164 // | | key. It is represented as the base64url encoding of the | | |
| 165 // | | value's unsigned big endian representation as an octet | | |
| 166 // | | sequence. | | |
| 167 // +-------+--------------------------------------------------------------+ | |
| 168 // | "dp" | Contains the first factor CRT exponent value for the RSA | | |
| 169 // | | private key. It is represented as the base64url encoding of | | |
| 170 // | | the value's unsigned big endian representation as an octet | | |
| 171 // | | sequence. | | |
| 172 // +-------+--------------------------------------------------------------+ | |
| 173 // | "dq" | Contains the second factor CRT exponent value for the RSA | | |
| 174 // | | private key. It is represented as the base64url encoding of | | |
| 175 // | | the value's unsigned big endian representation as an octet | | |
| 176 // | | sequence. | | |
| 177 // +-------+--------------------------------------------------------------+ | |
| 178 // | "dq" | Contains the first CRT coefficient value for the RSA private | | |
| 179 // | | key. It is represented as the base64url encoding of the | | |
| 180 // | | value's unsigned big endian representation as an octet | | |
| 181 // | | sequence. | | |
| 182 // +-------+--------------------------------------------------------------+ | |
| 153 // | 183 // |
| 154 // Consistency and conflict resolution | 184 // Consistency and conflict resolution |
| 155 // The 'algorithm', 'extractable', and 'usage_mask' input parameters | 185 // The 'algorithm', 'extractable', and 'usage_mask' input parameters |
| 156 // may be different than the corresponding values inside the JWK. The Web | 186 // may be different than the corresponding values inside the JWK. The Web |
| 157 // Crypto spec says that if a JWK value is present but is inconsistent with | 187 // Crypto spec says that if a JWK value is present but is inconsistent with |
| 158 // the input value, it is an error and the operation must fail. If no | 188 // the input value, it is an error and the operation must fail. If no |
| 159 // inconsistency is found then the input parameters are used. | 189 // inconsistency is found then the input parameters are used. |
| 160 // | 190 // |
| 161 // algorithm | 191 // algorithm |
| 162 // If the JWK algorithm is provided, it must match the web crypto input | 192 // If the JWK algorithm is provided, it must match the web crypto input |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 423 Status status = GetJwkString(dict, path, &base64_string); | 453 Status status = GetJwkString(dict, path, &base64_string); |
| 424 if (status.IsError()) | 454 if (status.IsError()) |
| 425 return status; | 455 return status; |
| 426 | 456 |
| 427 if (!Base64DecodeUrlSafe(base64_string, result)) | 457 if (!Base64DecodeUrlSafe(base64_string, result)) |
| 428 return Status::ErrorJwkBase64Decode(path); | 458 return Status::ErrorJwkBase64Decode(path); |
| 429 | 459 |
| 430 return Status::Success(); | 460 return Status::Success(); |
| 431 } | 461 } |
| 432 | 462 |
| 463 // Extracts the optional string property with key |path| from |dict| and saves | |
| 464 // the base64url-decoded bytes to |*result|. If the property exist and is not a | |
| 465 // string, or could not be base64url-decoded, returns an error. | |
| 466 Status GetOptionalJwkBytes(base::DictionaryValue* dict, | |
| 467 const std::string& path, | |
| 468 std::string* result, | |
| 469 bool* property_exists) { | |
| 470 std::string base64_string; | |
| 471 Status status = | |
| 472 GetOptionalJwkString(dict, path, &base64_string, property_exists); | |
| 473 if (!*property_exists || status.IsError()) | |
|
Ryan Sleevi
2014/05/19 00:10:34
nit: Check status.IsError() before doing *property
eroman
2014/05/19 18:51:09
Good point! Done.
Reading the boolean first could
| |
| 474 return status; | |
| 475 | |
| 476 if (!Base64DecodeUrlSafe(base64_string, result)) | |
| 477 return Status::ErrorJwkBase64Decode(path); | |
| 478 | |
| 479 return Status::Success(); | |
| 480 } | |
| 481 | |
| 433 // Extracts the optional boolean property with key |path| from |dict| and saves | 482 // Extracts the optional boolean property with key |path| from |dict| and saves |
| 434 // the result to |*result| if it was found. If the property exists and is not a | 483 // the result to |*result| if it was found. If the property exists and is not a |
| 435 // boolean, returns an error. Otherwise returns success, and sets | 484 // boolean, returns an error. Otherwise returns success, and sets |
| 436 // |*property_exists| if it was found. | 485 // |*property_exists| if it was found. |
| 437 Status GetOptionalJwkBool(base::DictionaryValue* dict, | 486 Status GetOptionalJwkBool(base::DictionaryValue* dict, |
| 438 const std::string& path, | 487 const std::string& path, |
| 439 bool* result, | 488 bool* result, |
| 440 bool* property_exists) { | 489 bool* property_exists) { |
| 441 *property_exists = false; | 490 *property_exists = false; |
| 442 base::Value* value = NULL; | 491 base::Value* value = NULL; |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 473 const std::vector<uint8>& public_exponent, | 522 const std::vector<uint8>& public_exponent, |
| 474 base::DictionaryValue* jwk_dict) { | 523 base::DictionaryValue* jwk_dict) { |
| 475 DCHECK(jwk_dict); | 524 DCHECK(jwk_dict); |
| 476 DCHECK(modulus.size()); | 525 DCHECK(modulus.size()); |
| 477 DCHECK(public_exponent.size()); | 526 DCHECK(public_exponent.size()); |
| 478 jwk_dict->SetString("kty", "RSA"); | 527 jwk_dict->SetString("kty", "RSA"); |
| 479 jwk_dict->SetString("n", Base64EncodeUrlSafe(modulus)); | 528 jwk_dict->SetString("n", Base64EncodeUrlSafe(modulus)); |
| 480 jwk_dict->SetString("e", Base64EncodeUrlSafe(public_exponent)); | 529 jwk_dict->SetString("e", Base64EncodeUrlSafe(public_exponent)); |
| 481 } | 530 } |
| 482 | 531 |
| 532 // Writes an RSA private key to a JWK dictionary | |
| 533 Status ExportRsaPrivateKeyJwk(const blink::WebCryptoKey& key, | |
| 534 base::DictionaryValue* jwk_dict) { | |
| 535 platform::PrivateKey* private_key; | |
| 536 Status status = ToPlatformPrivateKey(key, &private_key); | |
| 537 if (status.IsError()) | |
| 538 return status; | |
| 539 | |
| 540 // TODO(eroman): Copying the key properties to temporary vectors is | |
| 541 // inefficient. Once there aren't two implementations of platform_crypto this | |
| 542 // and other code will be easier to streamline. | |
| 543 std::vector<uint8> modulus; | |
| 544 std::vector<uint8> public_exponent; | |
| 545 std::vector<uint8> private_exponent; | |
| 546 std::vector<uint8> prime1; | |
| 547 std::vector<uint8> prime2; | |
| 548 std::vector<uint8> exponent1; | |
| 549 std::vector<uint8> exponent2; | |
| 550 std::vector<uint8> coefficient; | |
| 551 | |
| 552 status = platform::ExportRsaPrivateKey(private_key, | |
| 553 &modulus, | |
| 554 &public_exponent, | |
| 555 &private_exponent, | |
| 556 &prime1, | |
| 557 &prime2, | |
| 558 &exponent1, | |
| 559 &exponent2, | |
| 560 &coefficient); | |
| 561 if (status.IsError()) | |
| 562 return status; | |
| 563 | |
| 564 jwk_dict->SetString("kty", "RSA"); | |
| 565 jwk_dict->SetString("n", Base64EncodeUrlSafe(modulus)); | |
| 566 jwk_dict->SetString("e", Base64EncodeUrlSafe(public_exponent)); | |
| 567 jwk_dict->SetString("d", Base64EncodeUrlSafe(private_exponent)); | |
| 568 // Although these are "optional", the JWA spec says that producers | |
| 569 // SHOULD include them. | |
|
Ryan Sleevi
2014/05/19 00:10:34
Doesn't matter what JWA says. The WebCrypto spec i
eroman
2014/05/19 18:51:09
Done, updated the comment.
| |
| 570 jwk_dict->SetString("p", Base64EncodeUrlSafe(prime1)); | |
| 571 jwk_dict->SetString("q", Base64EncodeUrlSafe(prime2)); | |
| 572 jwk_dict->SetString("dp", Base64EncodeUrlSafe(exponent1)); | |
| 573 jwk_dict->SetString("dq", Base64EncodeUrlSafe(exponent2)); | |
| 574 jwk_dict->SetString("qi", Base64EncodeUrlSafe(coefficient)); | |
| 575 | |
| 576 return Status::Success(); | |
| 577 } | |
| 578 | |
| 483 // Writes a Web Crypto usage mask to a JWK dictionary. | 579 // Writes a Web Crypto usage mask to a JWK dictionary. |
| 484 void WriteKeyOps(blink::WebCryptoKeyUsageMask key_usages, | 580 void WriteKeyOps(blink::WebCryptoKeyUsageMask key_usages, |
| 485 base::DictionaryValue* jwk_dict) { | 581 base::DictionaryValue* jwk_dict) { |
| 486 jwk_dict->Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(key_usages)); | 582 jwk_dict->Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(key_usages)); |
| 487 } | 583 } |
| 488 | 584 |
| 489 // Writes a Web Crypto extractable value to a JWK dictionary. | 585 // Writes a Web Crypto extractable value to a JWK dictionary. |
| 490 void WriteExt(bool extractable, base::DictionaryValue* jwk_dict) { | 586 void WriteExt(bool extractable, base::DictionaryValue* jwk_dict) { |
| 491 jwk_dict->SetBoolean("ext", extractable); | 587 jwk_dict->SetBoolean("ext", extractable); |
| 492 } | 588 } |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 585 NOTREACHED(); | 681 NOTREACHED(); |
| 586 return Status::ErrorUnexpected(); | 682 return Status::ErrorUnexpected(); |
| 587 } | 683 } |
| 588 break; | 684 break; |
| 589 default: | 685 default: |
| 590 return Status::ErrorUnsupported(); | 686 return Status::ErrorUnsupported(); |
| 591 } | 687 } |
| 592 return Status::Success(); | 688 return Status::Success(); |
| 593 } | 689 } |
| 594 | 690 |
| 595 bool IsRsaPublicKey(const blink::WebCryptoKey& key) { | 691 bool IsRsaKey(const blink::WebCryptoKey& key) { |
| 596 if (key.type() != blink::WebCryptoKeyTypePublic) | |
| 597 return false; | |
| 598 const blink::WebCryptoAlgorithmId algorithm_id = key.algorithm().id(); | 692 const blink::WebCryptoAlgorithmId algorithm_id = key.algorithm().id(); |
| 599 return algorithm_id == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || | 693 return algorithm_id == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || |
| 600 algorithm_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || | 694 algorithm_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || |
| 601 algorithm_id == blink::WebCryptoAlgorithmIdRsaOaep; | 695 algorithm_id == blink::WebCryptoAlgorithmIdRsaOaep; |
| 602 } | 696 } |
| 603 | 697 |
| 604 // TODO(padolph): This function is duplicated in shared_crypto.cc | |
| 605 Status ToPlatformPublicKey(const blink::WebCryptoKey& key, | |
| 606 platform::PublicKey** out) { | |
| 607 *out = static_cast<platform::Key*>(key.handle())->AsPublicKey(); | |
| 608 if (!*out) | |
| 609 return Status::ErrorUnexpectedKeyType(); | |
| 610 return Status::Success(); | |
| 611 } | |
| 612 | |
| 613 } // namespace | 698 } // namespace |
| 614 | 699 |
| 700 // TODO(eroman): Split this up into smaller functions. | |
|
Ryan Sleevi
2014/05/19 00:10:34
I would rather see RSA Private key import split ou
eroman
2014/05/19 18:51:09
Done.
| |
| 615 Status ImportKeyJwk(const CryptoData& key_data, | 701 Status ImportKeyJwk(const CryptoData& key_data, |
| 616 const blink::WebCryptoAlgorithm& algorithm, | 702 const blink::WebCryptoAlgorithm& algorithm, |
| 617 bool extractable, | 703 bool extractable, |
| 618 blink::WebCryptoKeyUsageMask usage_mask, | 704 blink::WebCryptoKeyUsageMask usage_mask, |
| 619 blink::WebCryptoKey* key) { | 705 blink::WebCryptoKey* key) { |
| 620 if (!key_data.byte_length()) | 706 if (!key_data.byte_length()) |
| 621 return Status::ErrorImportEmptyKeyData(); | 707 return Status::ErrorImportEmptyKeyData(); |
| 622 DCHECK(key); | 708 DCHECK(key); |
| 623 | 709 |
| 624 // Parse the incoming JWK JSON. | 710 // Parse the incoming JWK JSON. |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 746 extractable, | 832 extractable, |
| 747 usage_mask, | 833 usage_mask, |
| 748 key); | 834 key); |
| 749 } | 835 } |
| 750 if (jwk_kty_value == "RSA") { | 836 if (jwk_kty_value == "RSA") { |
| 751 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry | 837 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry |
| 752 // in the JWK, while an RSA private key must have those, plus at least a "d" | 838 // in the JWK, while an RSA private key must have those, plus at least a "d" |
| 753 // (private exponent) entry. | 839 // (private exponent) entry. |
| 754 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18, | 840 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18, |
| 755 // section 6.3. | 841 // section 6.3. |
| 756 | |
| 757 // RSA private key import is not currently supported, so fail here if a "d" | |
| 758 // entry is found. | |
| 759 // TODO(padolph): Support RSA private key import. | |
| 760 if (dict_value->HasKey("d")) | |
| 761 return Status::ErrorJwkRsaPrivateKeyUnsupported(); | |
| 762 | |
| 763 std::string jwk_n_value; | 842 std::string jwk_n_value; |
| 764 status = GetJwkBytes(dict_value, "n", &jwk_n_value); | 843 status = GetJwkBytes(dict_value, "n", &jwk_n_value); |
| 765 if (status.IsError()) | 844 if (status.IsError()) |
| 766 return status; | 845 return status; |
| 767 std::string jwk_e_value; | 846 std::string jwk_e_value; |
| 768 status = GetJwkBytes(dict_value, "e", &jwk_e_value); | 847 status = GetJwkBytes(dict_value, "e", &jwk_e_value); |
| 769 if (status.IsError()) | 848 if (status.IsError()) |
| 770 return status; | 849 return status; |
| 771 | 850 |
| 772 return platform::ImportRsaPublicKey(algorithm, | 851 if (!dict_value->HasKey("d")) { |
| 773 extractable, | 852 return platform::ImportRsaPublicKey(algorithm, |
| 774 usage_mask, | 853 extractable, |
| 775 CryptoData(jwk_n_value), | 854 usage_mask, |
| 776 CryptoData(jwk_e_value), | 855 CryptoData(jwk_n_value), |
| 777 key); | 856 CryptoData(jwk_e_value), |
| 857 key); | |
| 858 } | |
| 778 | 859 |
| 860 std::string jwk_d_value; | |
| 861 status = GetJwkBytes(dict_value, "d", &jwk_d_value); | |
| 862 if (status.IsError()) | |
| 863 return status; | |
| 864 | |
| 865 std::string jwk_p_value; | |
| 866 bool has_p; | |
| 867 status = GetOptionalJwkBytes(dict_value, "p", &jwk_p_value, &has_p); | |
| 868 if (status.IsError()) | |
| 869 return status; | |
| 870 | |
| 871 std::string jwk_q_value; | |
| 872 bool has_q; | |
| 873 status = GetOptionalJwkBytes(dict_value, "q", &jwk_q_value, &has_q); | |
| 874 if (status.IsError()) | |
| 875 return status; | |
| 876 | |
| 877 std::string jwk_dp_value; | |
| 878 bool has_dp; | |
| 879 status = GetOptionalJwkBytes(dict_value, "dp", &jwk_dp_value, &has_dp); | |
| 880 if (status.IsError()) | |
| 881 return status; | |
| 882 | |
| 883 std::string jwk_dq_value; | |
| 884 bool has_dq; | |
| 885 status = GetOptionalJwkBytes(dict_value, "dq", &jwk_dq_value, &has_dq); | |
| 886 if (status.IsError()) | |
| 887 return status; | |
| 888 | |
| 889 std::string jwk_qi_value; | |
| 890 bool has_qi; | |
| 891 status = GetOptionalJwkBytes(dict_value, "qi", &jwk_qi_value, &has_qi); | |
| 892 if (status.IsError()) | |
| 893 return status; | |
| 894 | |
| 895 return platform::ImportRsaPrivateKey( | |
| 896 algorithm, | |
| 897 extractable, | |
| 898 usage_mask, | |
| 899 CryptoData(jwk_n_value), // modulus | |
| 900 CryptoData(jwk_e_value), // public_exponent | |
| 901 CryptoData(jwk_d_value), // private_exponent | |
| 902 has_p, | |
| 903 CryptoData(jwk_p_value), // prime1 | |
| 904 has_q, | |
| 905 CryptoData(jwk_q_value), // prime2 | |
| 906 has_dp, | |
| 907 CryptoData(jwk_dp_value), // exponent1 | |
| 908 has_dq, | |
| 909 CryptoData(jwk_dq_value), // exponent2 | |
| 910 has_qi, | |
| 911 CryptoData(jwk_qi_value), // coefficient | |
| 912 key); | |
| 779 } | 913 } |
| 780 | 914 |
| 781 return Status::ErrorJwkUnrecognizedKty(); | 915 return Status::ErrorJwkUnrecognizedKty(); |
| 782 } | 916 } |
| 783 | 917 |
| 784 Status ExportKeyJwk(const blink::WebCryptoKey& key, | 918 Status ExportKeyJwk(const blink::WebCryptoKey& key, |
| 785 std::vector<uint8>* buffer) { | 919 std::vector<uint8>* buffer) { |
| 786 DCHECK(key.extractable()); | 920 DCHECK(key.extractable()); |
| 787 base::DictionaryValue jwk_dict; | 921 base::DictionaryValue jwk_dict; |
| 788 Status status = Status::OperationError(); | 922 Status status = Status::OperationError(); |
| 789 | 923 |
| 790 switch (key.type()) { | 924 switch (key.type()) { |
| 791 case blink::WebCryptoKeyTypeSecret: { | 925 case blink::WebCryptoKeyTypeSecret: { |
| 792 std::vector<uint8> exported_key; | 926 std::vector<uint8> exported_key; |
| 793 status = ExportKey(blink::WebCryptoKeyFormatRaw, key, &exported_key); | 927 status = ExportKey(blink::WebCryptoKeyFormatRaw, key, &exported_key); |
| 794 if (status.IsError()) | 928 if (status.IsError()) |
| 795 return status; | 929 return status; |
| 796 WriteSecretKey(exported_key, &jwk_dict); | 930 WriteSecretKey(exported_key, &jwk_dict); |
| 797 break; | 931 break; |
| 798 } | 932 } |
| 799 case blink::WebCryptoKeyTypePublic: { | 933 case blink::WebCryptoKeyTypePublic: { |
| 800 // Currently only RSA public key export is supported. | 934 // TODO(eroman): Update when there are asymmetric keys other than RSA. |
| 801 if (!IsRsaPublicKey(key)) | 935 if (!IsRsaKey(key)) |
| 802 return Status::ErrorUnsupported(); | 936 return Status::ErrorUnsupported(); |
| 803 platform::PublicKey* public_key; | 937 platform::PublicKey* public_key; |
| 804 status = ToPlatformPublicKey(key, &public_key); | 938 status = ToPlatformPublicKey(key, &public_key); |
| 805 if (status.IsError()) | 939 if (status.IsError()) |
| 806 return status; | 940 return status; |
| 807 std::vector<uint8> modulus; | 941 std::vector<uint8> modulus; |
| 808 std::vector<uint8> public_exponent; | 942 std::vector<uint8> public_exponent; |
| 809 status = | 943 status = |
| 810 platform::ExportRsaPublicKey(public_key, &modulus, &public_exponent); | 944 platform::ExportRsaPublicKey(public_key, &modulus, &public_exponent); |
| 811 if (status.IsError()) | 945 if (status.IsError()) |
| 812 return status; | 946 return status; |
| 813 WriteRsaPublicKey(modulus, public_exponent, &jwk_dict); | 947 WriteRsaPublicKey(modulus, public_exponent, &jwk_dict); |
| 814 break; | 948 break; |
| 815 } | 949 } |
| 816 case blink::WebCryptoKeyTypePrivate: // TODO(padolph) | 950 case blink::WebCryptoKeyTypePrivate: { |
| 951 // TODO(eroman): Update when there are asymmetric keys other than RSA. | |
| 952 if (!IsRsaKey(key)) | |
| 953 return Status::ErrorUnsupported(); | |
| 954 | |
| 955 status = ExportRsaPrivateKeyJwk(key, &jwk_dict); | |
| 956 if (status.IsError()) | |
| 957 return status; | |
| 958 break; | |
| 959 } | |
| 960 | |
| 817 default: | 961 default: |
| 818 return Status::ErrorUnsupported(); | 962 return Status::ErrorUnsupported(); |
| 819 } | 963 } |
| 820 | 964 |
| 821 WriteKeyOps(key.usages(), &jwk_dict); | 965 WriteKeyOps(key.usages(), &jwk_dict); |
| 822 WriteExt(key.extractable(), &jwk_dict); | 966 WriteExt(key.extractable(), &jwk_dict); |
| 823 status = WriteAlg(key.algorithm(), &jwk_dict); | 967 status = WriteAlg(key.algorithm(), &jwk_dict); |
| 824 if (status.IsError()) | 968 if (status.IsError()) |
| 825 return status; | 969 return status; |
| 826 | 970 |
| 827 std::string json; | 971 std::string json; |
| 828 base::JSONWriter::Write(&jwk_dict, &json); | 972 base::JSONWriter::Write(&jwk_dict, &json); |
| 829 buffer->assign(json.data(), json.data() + json.size()); | 973 buffer->assign(json.data(), json.data() + json.size()); |
| 830 return Status::Success(); | 974 return Status::Success(); |
| 831 } | 975 } |
| 832 | 976 |
| 833 } // namespace webcrypto | 977 } // namespace webcrypto |
| 834 | 978 |
| 835 } // namespace content | 979 } // namespace content |
| OLD | NEW |