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

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

Issue 379383002: Refactor WebCrypto code (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase onto master Created 6 years, 5 months 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 | Annotate | Revision Log
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 "jwk.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <functional> 8 #include <functional>
9 #include <map> 9 #include <map>
10 10
11 #include "base/json/json_reader.h" 11 #include "base/json/json_reader.h"
12 #include "base/json/json_writer.h" 12 #include "base/json/json_writer.h"
13 #include "base/lazy_instance.h"
14 #include "base/strings/string_piece.h" 13 #include "base/strings/string_piece.h"
15 #include "base/strings/stringprintf.h"
16 #include "content/child/webcrypto/crypto_data.h" 14 #include "content/child/webcrypto/crypto_data.h"
17 #include "content/child/webcrypto/platform_crypto.h"
18 #include "content/child/webcrypto/shared_crypto.h"
19 #include "content/child/webcrypto/status.h" 15 #include "content/child/webcrypto/status.h"
20 #include "content/child/webcrypto/webcrypto_util.h" 16 #include "content/child/webcrypto/webcrypto_util.h"
21 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
22 17
23 // JSON Web Key Format (JWK) 18 // JSON Web Key Format (JWK)
24 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-21 19 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-21
25 // 20 //
26 // A JWK is a simple JSON dictionary with the following entries 21 // A JWK is a simple JSON dictionary with the following entries
27 // - "kty" (Key Type) Parameter, REQUIRED 22 // - "kty" (Key Type) Parameter, REQUIRED
28 // - <kty-specific parameters, see below>, REQUIRED 23 // - <kty-specific parameters, see below>, REQUIRED
29 // - "use" (Key Use) Parameter, OPTIONAL 24 // - "use" (Key Use) Parameter, OPTIONAL
30 // - "key_ops" (Key Operations) Parameter, OPTIONAL 25 // - "key_ops" (Key Operations) Parameter, OPTIONAL
31 // - "alg" (Algorithm) Parameter, OPTIONAL 26 // - "alg" (Algorithm) Parameter, OPTIONAL
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 // value, else it is judged inconsistent. In all cases the input usage_mask 197 // value, else it is judged inconsistent. In all cases the input usage_mask
203 // is used as the final usage_mask. 198 // is used as the final usage_mask.
204 // 199 //
205 200
206 namespace content { 201 namespace content {
207 202
208 namespace webcrypto { 203 namespace webcrypto {
209 204
210 namespace { 205 namespace {
211 206
212 // Creates an RSASSA-PKCS1-v1_5 algorithm. It is an error to call this with a
213 // hash_id that is not a SHA*.
214 blink::WebCryptoAlgorithm CreateRsaSsaImportAlgorithm(
215 blink::WebCryptoAlgorithmId hash_id) {
216 return CreateRsaHashedImportAlgorithm(
217 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, hash_id);
218 }
219
220 // Creates an RSA-OAEP algorithm. It is an error to call this with a hash_id
221 // that is not a SHA*.
222 blink::WebCryptoAlgorithm CreateRsaOaepImportAlgorithm(
223 blink::WebCryptoAlgorithmId hash_id) {
224 return CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep,
225 hash_id);
226 }
227
228 // Web Crypto equivalent usage mask for JWK 'use' = 'enc'. 207 // Web Crypto equivalent usage mask for JWK 'use' = 'enc'.
229 const blink::WebCryptoKeyUsageMask kJwkEncUsage = 208 const blink::WebCryptoKeyUsageMask kJwkEncUsage =
230 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt | 209 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
231 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey | 210 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey |
232 blink::WebCryptoKeyUsageDeriveKey | blink::WebCryptoKeyUsageDeriveBits; 211 blink::WebCryptoKeyUsageDeriveKey | blink::WebCryptoKeyUsageDeriveBits;
233 // Web Crypto equivalent usage mask for JWK 'use' = 'sig'. 212 // Web Crypto equivalent usage mask for JWK 'use' = 'sig'.
234 const blink::WebCryptoKeyUsageMask kJwkSigUsage = 213 const blink::WebCryptoKeyUsageMask kJwkSigUsage =
235 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; 214 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
236 215
237 typedef blink::WebCryptoAlgorithm (*AlgorithmCreationFunc)(); 216 class JwkWriter {
238
239 class JwkAlgorithmInfo {
240 public: 217 public:
241 JwkAlgorithmInfo() 218 JwkWriter(const std::string& algorithm,
242 : creation_func_(NULL), 219 bool extractable,
243 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {} 220 blink::WebCryptoKeyUsageMask usage_mask,
244 221 const std::string& kty) {
245 explicit JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func) 222 dict_.SetString("alg", algorithm);
246 : creation_func_(algorithm_creation_func), 223 dict_.Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(usage_mask));
247 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {} 224 dict_.SetBoolean("ext", extractable);
248 225 dict_.SetString("kty", kty);
249 JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func,
250 unsigned int required_key_length_bits)
251 : creation_func_(algorithm_creation_func),
252 required_key_length_bytes_(required_key_length_bits / 8) {
253 DCHECK_EQ(0u, required_key_length_bits % 8);
254 } 226 }
255 227
256 bool CreateImportAlgorithm(blink::WebCryptoAlgorithm* algorithm) const { 228 void Set(const std::string& key, const std::string& value) {
257 *algorithm = creation_func_(); 229 dict_.SetString(key, value);
258 return !algorithm->isNull();
259 } 230 }
260 231
261 bool IsInvalidKeyByteLength(size_t byte_length) const { 232 void SetBase64Encoded(const std::string& key, const CryptoData& value) {
262 if (required_key_length_bytes_ == NO_KEY_SIZE_REQUIREMENT) 233 dict_.SetString(key,
263 return false; 234 Base64EncodeUrlSafe(base::StringPiece(
264 return required_key_length_bytes_ != byte_length; 235 reinterpret_cast<const char*>(value.bytes()),
236 value.byte_length())));
237 }
238
239 void ToBytes(std::vector<uint8>* utf8_bytes) {
240 std::string json;
241 base::JSONWriter::Write(&dict_, &json);
242 utf8_bytes->assign(json.data(), json.data() + json.size());
Ryan Sleevi 2014/07/12 00:55:27 Why don't you need to cast here? json is std::str
eroman 2014/07/12 01:59:30 Done.
265 } 243 }
266 244
267 private: 245 private:
268 enum { NO_KEY_SIZE_REQUIREMENT = UINT_MAX }; 246 base::DictionaryValue dict_;
269
270 AlgorithmCreationFunc creation_func_;
271
272 // The expected key size for the algorithm or NO_KEY_SIZE_REQUIREMENT.
273 unsigned int required_key_length_bytes_;
274 }; 247 };
275 248
276 typedef std::map<std::string, JwkAlgorithmInfo> JwkAlgorithmInfoMap;
277
278 class JwkAlgorithmRegistry {
279 public:
280 JwkAlgorithmRegistry() {
281 // TODO(eroman):
282 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-20
283 // says HMAC with SHA-2 should have a key size at least as large as the
284 // hash output.
285 alg_to_info_["HS1"] =
286 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm,
287 blink::WebCryptoAlgorithmIdSha1>);
288 alg_to_info_["HS256"] =
289 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm,
290 blink::WebCryptoAlgorithmIdSha256>);
291 alg_to_info_["HS384"] =
292 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm,
293 blink::WebCryptoAlgorithmIdSha384>);
294 alg_to_info_["HS512"] =
295 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm,
296 blink::WebCryptoAlgorithmIdSha512>);
297 alg_to_info_["RS1"] =
298 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm,
299 blink::WebCryptoAlgorithmIdSha1>);
300 alg_to_info_["RS256"] =
301 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm,
302 blink::WebCryptoAlgorithmIdSha256>);
303 alg_to_info_["RS384"] =
304 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm,
305 blink::WebCryptoAlgorithmIdSha384>);
306 alg_to_info_["RS512"] =
307 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm,
308 blink::WebCryptoAlgorithmIdSha512>);
309 alg_to_info_["RSA-OAEP"] =
310 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaOaepImportAlgorithm,
311 blink::WebCryptoAlgorithmIdSha1>);
312 alg_to_info_["RSA-OAEP-256"] =
313 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaOaepImportAlgorithm,
314 blink::WebCryptoAlgorithmIdSha256>);
315 alg_to_info_["RSA-OAEP-384"] =
316 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaOaepImportAlgorithm,
317 blink::WebCryptoAlgorithmIdSha384>);
318 alg_to_info_["RSA-OAEP-512"] =
319 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaOaepImportAlgorithm,
320 blink::WebCryptoAlgorithmIdSha512>);
321 alg_to_info_["A128KW"] = JwkAlgorithmInfo(
322 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesKw>,
323 128);
324 alg_to_info_["A192KW"] = JwkAlgorithmInfo(
325 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesKw>,
326 192);
327 alg_to_info_["A256KW"] = JwkAlgorithmInfo(
328 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesKw>,
329 256);
330 alg_to_info_["A128GCM"] = JwkAlgorithmInfo(
331 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesGcm>,
332 128);
333 alg_to_info_["A192GCM"] = JwkAlgorithmInfo(
334 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesGcm>,
335 192);
336 alg_to_info_["A256GCM"] = JwkAlgorithmInfo(
337 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesGcm>,
338 256);
339 alg_to_info_["A128CBC"] = JwkAlgorithmInfo(
340 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesCbc>,
341 128);
342 alg_to_info_["A192CBC"] = JwkAlgorithmInfo(
343 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesCbc>,
344 192);
345 alg_to_info_["A256CBC"] = JwkAlgorithmInfo(
346 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesCbc>,
347 256);
348 }
349
350 // Returns NULL if the algorithm name was not registered.
351 const JwkAlgorithmInfo* GetAlgorithmInfo(const std::string& jwk_alg) const {
352 const JwkAlgorithmInfoMap::const_iterator pos = alg_to_info_.find(jwk_alg);
353 if (pos == alg_to_info_.end())
354 return NULL;
355 return &pos->second;
356 }
357
358 private:
359 // Binds a WebCryptoAlgorithmId value to a compatible factory function.
360 typedef blink::WebCryptoAlgorithm (*FuncWithWebCryptoAlgIdArg)(
361 blink::WebCryptoAlgorithmId);
362 template <FuncWithWebCryptoAlgIdArg func,
363 blink::WebCryptoAlgorithmId algorithm_id>
364 static blink::WebCryptoAlgorithm BindAlgorithmId() {
365 return func(algorithm_id);
366 }
367
368 JwkAlgorithmInfoMap alg_to_info_;
369 };
370
371 base::LazyInstance<JwkAlgorithmRegistry> jwk_alg_registry =
372 LAZY_INSTANCE_INITIALIZER;
373
374 bool ImportAlgorithmsConsistent(const blink::WebCryptoAlgorithm& alg1,
375 const blink::WebCryptoAlgorithm& alg2) {
376 DCHECK(!alg1.isNull());
377 DCHECK(!alg2.isNull());
378 if (alg1.id() != alg2.id())
379 return false;
380 if (alg1.paramsType() != alg2.paramsType())
381 return false;
382 switch (alg1.paramsType()) {
383 case blink::WebCryptoAlgorithmParamsTypeNone:
384 return true;
385 case blink::WebCryptoAlgorithmParamsTypeRsaHashedImportParams:
386 return ImportAlgorithmsConsistent(alg1.rsaHashedImportParams()->hash(),
387 alg2.rsaHashedImportParams()->hash());
388 case blink::WebCryptoAlgorithmParamsTypeHmacImportParams:
389 return ImportAlgorithmsConsistent(alg1.hmacImportParams()->hash(),
390 alg2.hmacImportParams()->hash());
391 default:
392 return false;
393 }
394 }
395
396 // Extracts the required string property with key |path| from |dict| and saves 249 // Extracts the required string property with key |path| from |dict| and saves
397 // the result to |*result|. If the property does not exist or is not a string, 250 // the result to |*result|. If the property does not exist or is not a string,
398 // returns an error. 251 // returns an error.
399 Status GetJwkString(base::DictionaryValue* dict, 252 Status GetJwkString(base::DictionaryValue* dict,
400 const std::string& path, 253 const std::string& path,
401 std::string* result) { 254 std::string* result) {
402 base::Value* value = NULL; 255 base::Value* value = NULL;
403 if (!dict->Get(path, &value)) 256 if (!dict->Get(path, &value))
404 return Status::ErrorJwkPropertyMissing(path); 257 return Status::ErrorJwkPropertyMissing(path);
405 if (!value->GetAsString(result)) 258 if (!value->GetAsString(result))
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
502 if (!dict->Get(path, &value)) 355 if (!dict->Get(path, &value))
503 return Status::Success(); 356 return Status::Success();
504 357
505 if (!value->GetAsBoolean(result)) 358 if (!value->GetAsBoolean(result))
506 return Status::ErrorJwkPropertyWrongType(path, "boolean"); 359 return Status::ErrorJwkPropertyWrongType(path, "boolean");
507 360
508 *property_exists = true; 361 *property_exists = true;
509 return Status::Success(); 362 return Status::Success();
510 } 363 }
511 364
512 // Writes a secret/symmetric key to a JWK dictionary. 365 Status VerifyExt(base::DictionaryValue* dict, bool expected_extractable) {
513 void WriteSecretKey(const std::vector<uint8>& raw_key,
514 base::DictionaryValue* jwk_dict) {
515 DCHECK(jwk_dict);
516 jwk_dict->SetString("kty", "oct");
517 // For a secret/symmetric key, the only extra JWK field is 'k', containing the
518 // base64url encoding of the raw key.
519 const base::StringPiece key_str(
520 reinterpret_cast<const char*>(Uint8VectorStart(raw_key)), raw_key.size());
521 jwk_dict->SetString("k", Base64EncodeUrlSafe(key_str));
522 }
523
524 // Writes an RSA public key to a JWK dictionary
525 void WriteRsaPublicKey(const std::vector<uint8>& modulus,
526 const std::vector<uint8>& public_exponent,
527 base::DictionaryValue* jwk_dict) {
528 DCHECK(jwk_dict);
529 DCHECK(modulus.size());
530 DCHECK(public_exponent.size());
531 jwk_dict->SetString("kty", "RSA");
532 jwk_dict->SetString("n", Base64EncodeUrlSafe(modulus));
533 jwk_dict->SetString("e", Base64EncodeUrlSafe(public_exponent));
534 }
535
536 // Writes an RSA private key to a JWK dictionary
537 Status ExportRsaPrivateKeyJwk(const blink::WebCryptoKey& key,
538 base::DictionaryValue* jwk_dict) {
539 platform::PrivateKey* private_key;
540 Status status = ToPlatformPrivateKey(key, &private_key);
541 if (status.IsError())
542 return status;
543
544 // TODO(eroman): Copying the key properties to temporary vectors is
545 // inefficient. Once there aren't two implementations of platform_crypto this
546 // and other code will be easier to streamline.
547 std::vector<uint8> modulus;
548 std::vector<uint8> public_exponent;
549 std::vector<uint8> private_exponent;
550 std::vector<uint8> prime1;
551 std::vector<uint8> prime2;
552 std::vector<uint8> exponent1;
553 std::vector<uint8> exponent2;
554 std::vector<uint8> coefficient;
555
556 status = platform::ExportRsaPrivateKey(private_key,
557 &modulus,
558 &public_exponent,
559 &private_exponent,
560 &prime1,
561 &prime2,
562 &exponent1,
563 &exponent2,
564 &coefficient);
565 if (status.IsError())
566 return status;
567
568 jwk_dict->SetString("kty", "RSA");
569 jwk_dict->SetString("n", Base64EncodeUrlSafe(modulus));
570 jwk_dict->SetString("e", Base64EncodeUrlSafe(public_exponent));
571 jwk_dict->SetString("d", Base64EncodeUrlSafe(private_exponent));
572 // Although these are "optional" in the JWA, WebCrypto spec requires them to
573 // be emitted.
574 jwk_dict->SetString("p", Base64EncodeUrlSafe(prime1));
575 jwk_dict->SetString("q", Base64EncodeUrlSafe(prime2));
576 jwk_dict->SetString("dp", Base64EncodeUrlSafe(exponent1));
577 jwk_dict->SetString("dq", Base64EncodeUrlSafe(exponent2));
578 jwk_dict->SetString("qi", Base64EncodeUrlSafe(coefficient));
579
580 return Status::Success();
581 }
582
583 // Writes a Web Crypto usage mask to a JWK dictionary.
584 void WriteKeyOps(blink::WebCryptoKeyUsageMask key_usages,
585 base::DictionaryValue* jwk_dict) {
586 jwk_dict->Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(key_usages));
587 }
588
589 // Writes a Web Crypto extractable value to a JWK dictionary.
590 void WriteExt(bool extractable, base::DictionaryValue* jwk_dict) {
591 jwk_dict->SetBoolean("ext", extractable);
592 }
593
594 // Writes a Web Crypto algorithm to a JWK dictionary.
595 Status WriteAlg(const blink::WebCryptoKeyAlgorithm& algorithm,
596 base::DictionaryValue* jwk_dict) {
597 switch (algorithm.paramsType()) {
598 case blink::WebCryptoKeyAlgorithmParamsTypeAes: {
599 DCHECK(algorithm.aesParams());
600 const char* aes_prefix = "";
601 switch (algorithm.aesParams()->lengthBits()) {
602 case 128:
603 aes_prefix = "A128";
604 break;
605 case 192:
606 aes_prefix = "A192";
607 break;
608 case 256:
609 aes_prefix = "A256";
610 break;
611 default:
612 NOTREACHED(); // bad key length means algorithm was built improperly
613 return Status::ErrorUnexpected();
614 }
615 const char* aes_suffix = "";
616 switch (algorithm.id()) {
617 case blink::WebCryptoAlgorithmIdAesCbc:
618 aes_suffix = "CBC";
619 break;
620 case blink::WebCryptoAlgorithmIdAesCtr:
621 aes_suffix = "CTR";
622 break;
623 case blink::WebCryptoAlgorithmIdAesGcm:
624 aes_suffix = "GCM";
625 break;
626 case blink::WebCryptoAlgorithmIdAesKw:
627 aes_suffix = "KW";
628 break;
629 default:
630 return Status::ErrorUnsupported();
631 }
632 jwk_dict->SetString("alg",
633 base::StringPrintf("%s%s", aes_prefix, aes_suffix));
634 break;
635 }
636 case blink::WebCryptoKeyAlgorithmParamsTypeHmac: {
637 DCHECK(algorithm.hmacParams());
638 switch (algorithm.hmacParams()->hash().id()) {
639 case blink::WebCryptoAlgorithmIdSha1:
640 jwk_dict->SetString("alg", "HS1");
641 break;
642 case blink::WebCryptoAlgorithmIdSha256:
643 jwk_dict->SetString("alg", "HS256");
644 break;
645 case blink::WebCryptoAlgorithmIdSha384:
646 jwk_dict->SetString("alg", "HS384");
647 break;
648 case blink::WebCryptoAlgorithmIdSha512:
649 jwk_dict->SetString("alg", "HS512");
650 break;
651 default:
652 NOTREACHED();
653 return Status::ErrorUnexpected();
654 }
655 break;
656 }
657 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed:
658 switch (algorithm.id()) {
659 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: {
660 switch (algorithm.rsaHashedParams()->hash().id()) {
661 case blink::WebCryptoAlgorithmIdSha1:
662 jwk_dict->SetString("alg", "RS1");
663 break;
664 case blink::WebCryptoAlgorithmIdSha256:
665 jwk_dict->SetString("alg", "RS256");
666 break;
667 case blink::WebCryptoAlgorithmIdSha384:
668 jwk_dict->SetString("alg", "RS384");
669 break;
670 case blink::WebCryptoAlgorithmIdSha512:
671 jwk_dict->SetString("alg", "RS512");
672 break;
673 default:
674 NOTREACHED();
675 return Status::ErrorUnexpected();
676 }
677 break;
678 }
679 case blink::WebCryptoAlgorithmIdRsaOaep: {
680 switch (algorithm.rsaHashedParams()->hash().id()) {
681 case blink::WebCryptoAlgorithmIdSha1:
682 jwk_dict->SetString("alg", "RSA-OAEP");
683 break;
684 case blink::WebCryptoAlgorithmIdSha256:
685 jwk_dict->SetString("alg", "RSA-OAEP-256");
686 break;
687 case blink::WebCryptoAlgorithmIdSha384:
688 jwk_dict->SetString("alg", "RSA-OAEP-384");
689 break;
690 case blink::WebCryptoAlgorithmIdSha512:
691 jwk_dict->SetString("alg", "RSA-OAEP-512");
692 break;
693 default:
694 NOTREACHED();
695 return Status::ErrorUnexpected();
696 }
697 break;
698 }
699 default:
700 NOTREACHED();
701 return Status::ErrorUnexpected();
702 }
703 break;
704 default:
705 return Status::ErrorUnsupported();
706 }
707 return Status::Success();
708 }
709
710 bool IsRsaKey(const blink::WebCryptoKey& key) {
711 return IsAlgorithmRsa(key.algorithm().id());
712 }
713
714 Status ImportRsaKey(base::DictionaryValue* dict,
715 const blink::WebCryptoAlgorithm& algorithm,
716 bool extractable,
717 blink::WebCryptoKeyUsageMask usage_mask,
718 blink::WebCryptoKey* key) {
719 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
720 // in the JWK, while an RSA private key must have those, plus at least a "d"
721 // (private exponent) entry.
722 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
723 // section 6.3.
724 std::string jwk_n_value;
725 Status status = GetJwkBytes(dict, "n", &jwk_n_value);
726 if (status.IsError())
727 return status;
728 std::string jwk_e_value;
729 status = GetJwkBytes(dict, "e", &jwk_e_value);
730 if (status.IsError())
731 return status;
732
733 bool is_public_key = !dict->HasKey("d");
734
735 // Now that the key type is known, do an additional check on the usages to
736 // make sure they are all applicable for this algorithm + key type.
737 status = CheckKeyUsages(algorithm.id(),
738 is_public_key ? blink::WebCryptoKeyTypePublic
739 : blink::WebCryptoKeyTypePrivate,
740 usage_mask);
741
742 if (status.IsError())
743 return status;
744
745 if (is_public_key) {
746 return platform::ImportRsaPublicKey(algorithm,
747 extractable,
748 usage_mask,
749 CryptoData(jwk_n_value),
750 CryptoData(jwk_e_value),
751 key);
752 }
753
754 std::string jwk_d_value;
755 status = GetJwkBytes(dict, "d", &jwk_d_value);
756 if (status.IsError())
757 return status;
758
759 // The "p", "q", "dp", "dq", and "qi" properties are optional. Treat these
760 // properties the same if they are unspecified, as if they were specified-but
761 // empty, since ImportRsaPrivateKey() doesn't do validation checks anyway.
762
763 std::string jwk_p_value;
764 bool has_p;
765 status = GetOptionalJwkBytes(dict, "p", &jwk_p_value, &has_p);
766 if (status.IsError())
767 return status;
768
769 std::string jwk_q_value;
770 bool has_q;
771 status = GetOptionalJwkBytes(dict, "q", &jwk_q_value, &has_q);
772 if (status.IsError())
773 return status;
774
775 std::string jwk_dp_value;
776 bool has_dp;
777 status = GetOptionalJwkBytes(dict, "dp", &jwk_dp_value, &has_dp);
778 if (status.IsError())
779 return status;
780
781 std::string jwk_dq_value;
782 bool has_dq;
783 status = GetOptionalJwkBytes(dict, "dq", &jwk_dq_value, &has_dq);
784 if (status.IsError())
785 return status;
786
787 std::string jwk_qi_value;
788 bool has_qi;
789 status = GetOptionalJwkBytes(dict, "qi", &jwk_qi_value, &has_qi);
790 if (status.IsError())
791 return status;
792
793 int num_optional_properties = has_p + has_q + has_dp + has_dq + has_qi;
794 if (num_optional_properties != 0 && num_optional_properties != 5)
795 return Status::ErrorJwkIncompleteOptionalRsaPrivateKey();
796
797 return platform::ImportRsaPrivateKey(
798 algorithm,
799 extractable,
800 usage_mask,
801 CryptoData(jwk_n_value), // modulus
802 CryptoData(jwk_e_value), // public_exponent
803 CryptoData(jwk_d_value), // private_exponent
804 CryptoData(jwk_p_value), // prime1
805 CryptoData(jwk_q_value), // prime2
806 CryptoData(jwk_dp_value), // exponent1
807 CryptoData(jwk_dq_value), // exponent2
808 CryptoData(jwk_qi_value), // coefficient
809 key);
810 }
811
812 } // namespace
813
814 // TODO(eroman): Split this up into smaller functions.
815 Status ImportKeyJwk(const CryptoData& key_data,
816 const blink::WebCryptoAlgorithm& algorithm,
817 bool extractable,
818 blink::WebCryptoKeyUsageMask usage_mask,
819 blink::WebCryptoKey* key) {
820 if (!key_data.byte_length())
821 return Status::ErrorImportEmptyKeyData();
822 DCHECK(key);
823
824 // Parse the incoming JWK JSON.
825 base::StringPiece json_string(reinterpret_cast<const char*>(key_data.bytes()),
826 key_data.byte_length());
827 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
828 // Note, bare pointer dict_value is ok since it points into scoped value.
829 base::DictionaryValue* dict_value = NULL;
830 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value)
831 return Status::ErrorJwkNotDictionary();
832
833 // JWK "kty". Exit early if this required JWK parameter is missing.
834 std::string jwk_kty_value;
835 Status status = GetJwkString(dict_value, "kty", &jwk_kty_value);
836 if (status.IsError())
837 return status;
838
839 // JWK "ext" (optional) --> extractable parameter 366 // JWK "ext" (optional) --> extractable parameter
840 { 367 bool jwk_ext_value = false;
841 bool jwk_ext_value = false; 368 bool has_jwk_ext;
842 bool has_jwk_ext; 369 Status status = GetOptionalJwkBool(dict, "ext", &jwk_ext_value, &has_jwk_ext);
843 status = 370 if (status.IsError())
844 GetOptionalJwkBool(dict_value, "ext", &jwk_ext_value, &has_jwk_ext); 371 return status;
845 if (status.IsError()) 372 if (has_jwk_ext && expected_extractable && !jwk_ext_value)
846 return status; 373 return Status::ErrorJwkExtInconsistent();
847 if (has_jwk_ext && !jwk_ext_value && extractable) 374 return Status::Success();
848 return Status::ErrorJwkExtInconsistent(); 375 }
849 } 376
850 377 Status VerifyUsages(base::DictionaryValue* dict,
851 // JWK "alg" --> algorithm parameter 378 blink::WebCryptoKeyUsageMask expected_usage_mask) {
852 // 1. JWK alg present but unrecognized: error
853 // 2. JWK alg valid and inconsistent with input algorithm: error
854 // 3. JWK alg valid and consistent with input algorithm: use input value
855 // 4. JWK alg is missing: use input value
856 const JwkAlgorithmInfo* algorithm_info = NULL;
857 std::string jwk_alg_value;
858 bool has_jwk_alg;
859 status =
860 GetOptionalJwkString(dict_value, "alg", &jwk_alg_value, &has_jwk_alg);
861 if (status.IsError())
862 return status;
863
864 if (has_jwk_alg) {
865 // JWK alg present
866
867 // TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can
868 // only be from the RSA family.
869
870 blink::WebCryptoAlgorithm jwk_algorithm =
871 blink::WebCryptoAlgorithm::createNull();
872 algorithm_info = jwk_alg_registry.Get().GetAlgorithmInfo(jwk_alg_value);
873 if (!algorithm_info ||
874 !algorithm_info->CreateImportAlgorithm(&jwk_algorithm))
875 return Status::ErrorJwkUnrecognizedAlgorithm();
876
877 if (!ImportAlgorithmsConsistent(jwk_algorithm, algorithm))
878 return Status::ErrorJwkAlgorithmInconsistent();
879 }
880 DCHECK(!algorithm.isNull());
881
882 // JWK "key_ops" (optional) --> usage_mask parameter 379 // JWK "key_ops" (optional) --> usage_mask parameter
883 base::ListValue* jwk_key_ops_value = NULL; 380 base::ListValue* jwk_key_ops_value = NULL;
884 bool has_jwk_key_ops; 381 bool has_jwk_key_ops;
885 status = GetOptionalJwkList( 382 Status status =
886 dict_value, "key_ops", &jwk_key_ops_value, &has_jwk_key_ops); 383 GetOptionalJwkList(dict, "key_ops", &jwk_key_ops_value, &has_jwk_key_ops);
887 if (status.IsError()) 384 if (status.IsError())
888 return status; 385 return status;
889 blink::WebCryptoKeyUsageMask jwk_key_ops_mask = 0; 386 blink::WebCryptoKeyUsageMask jwk_key_ops_mask = 0;
890 if (has_jwk_key_ops) { 387 if (has_jwk_key_ops) {
891 status = 388 status =
892 GetWebCryptoUsagesFromJwkKeyOps(jwk_key_ops_value, &jwk_key_ops_mask); 389 GetWebCryptoUsagesFromJwkKeyOps(jwk_key_ops_value, &jwk_key_ops_mask);
893 if (status.IsError()) 390 if (status.IsError())
894 return status; 391 return status;
895 // The input usage_mask must be a subset of jwk_key_ops_mask. 392 // The input usage_mask must be a subset of jwk_key_ops_mask.
896 if (!ContainsKeyUsages(jwk_key_ops_mask, usage_mask)) 393 if (!ContainsKeyUsages(jwk_key_ops_mask, expected_usage_mask))
897 return Status::ErrorJwkKeyopsInconsistent(); 394 return Status::ErrorJwkKeyopsInconsistent();
898 } 395 }
899 396
900 // JWK "use" (optional) --> usage_mask parameter 397 // JWK "use" (optional) --> usage_mask parameter
901 std::string jwk_use_value; 398 std::string jwk_use_value;
902 bool has_jwk_use; 399 bool has_jwk_use;
903 status = 400 status = GetOptionalJwkString(dict, "use", &jwk_use_value, &has_jwk_use);
904 GetOptionalJwkString(dict_value, "use", &jwk_use_value, &has_jwk_use);
905 if (status.IsError()) 401 if (status.IsError())
906 return status; 402 return status;
907 blink::WebCryptoKeyUsageMask jwk_use_mask = 0; 403 blink::WebCryptoKeyUsageMask jwk_use_mask = 0;
908 if (has_jwk_use) { 404 if (has_jwk_use) {
909 if (jwk_use_value == "enc") 405 if (jwk_use_value == "enc")
910 jwk_use_mask = kJwkEncUsage; 406 jwk_use_mask = kJwkEncUsage;
911 else if (jwk_use_value == "sig") 407 else if (jwk_use_value == "sig")
912 jwk_use_mask = kJwkSigUsage; 408 jwk_use_mask = kJwkSigUsage;
913 else 409 else
914 return Status::ErrorJwkUnrecognizedUse(); 410 return Status::ErrorJwkUnrecognizedUse();
915 // The input usage_mask must be a subset of jwk_use_mask. 411 // The input usage_mask must be a subset of jwk_use_mask.
916 if (!ContainsKeyUsages(jwk_use_mask, usage_mask)) 412 if (!ContainsKeyUsages(jwk_use_mask, expected_usage_mask))
917 return Status::ErrorJwkUseInconsistent(); 413 return Status::ErrorJwkUseInconsistent();
918 } 414 }
919 415
920 // If both 'key_ops' and 'use' are present, ensure they are consistent. 416 // If both 'key_ops' and 'use' are present, ensure they are consistent.
921 if (has_jwk_key_ops && has_jwk_use && 417 if (has_jwk_key_ops && has_jwk_use &&
922 !ContainsKeyUsages(jwk_use_mask, jwk_key_ops_mask)) 418 !ContainsKeyUsages(jwk_use_mask, jwk_key_ops_mask))
923 return Status::ErrorJwkUseAndKeyopsInconsistent(); 419 return Status::ErrorJwkUseAndKeyopsInconsistent();
924 420
925 // JWK keying material --> ImportKeyInternal() 421 return Status::Success();
926 if (jwk_kty_value == "oct") { 422 }
927 std::string jwk_k_value; 423
928 status = GetJwkBytes(dict_value, "k", &jwk_k_value); 424 Status VerifyAlg(base::DictionaryValue* dict,
929 if (status.IsError()) 425 const std::string& expected_algorithm,
930 return status; 426 std::string* actual_algorithm) {
931 427 // JWK "alg" --> algorithm parameter
932 // Some JWK alg ID's embed information about the key length in the alg ID 428 bool has_jwk_alg;
933 // string. For example "A128CBC" implies the JWK carries 128 bits 429 std::string jwk_alg_value;
934 // of key material. For such keys validate that enough bytes were provided. 430 Status status =
935 // If this validation is not done, then it would be possible to select a 431 GetOptionalJwkString(dict, "alg", &jwk_alg_value, &has_jwk_alg);
936 // different algorithm by passing a different lengthed key, since that is 432 if (status.IsError())
937 // how WebCrypto interprets things. 433 return status;
938 if (algorithm_info && 434 if (actual_algorithm) {
939 algorithm_info->IsInvalidKeyByteLength(jwk_k_value.size())) { 435 if (has_jwk_alg) {
436 if (jwk_alg_value.empty())
437 return Status::ErrorJwkAlgorithmInconsistent();
Ryan Sleevi 2014/07/12 00:55:27 Why do you place this check here, but then you ret
eroman 2014/07/12 01:59:30 Thanks for pointing this out, the current structur
eroman 2014/07/14 21:56:10 Done.
438 *actual_algorithm = jwk_alg_value;
439 } else {
440 *actual_algorithm = std::string();
441 }
442 }
443
444 if (has_jwk_alg && !expected_algorithm.empty() &&
445 jwk_alg_value != expected_algorithm) {
446 return Status::ErrorJwkAlgorithmInconsistent();
447 }
448
449 return Status::Success();
450 }
451
452 Status ParseJwkCommon(const CryptoData& bytes,
453 const std::string& expected_algorithm,
454 bool expected_extractable,
455 blink::WebCryptoKeyUsageMask expected_usage_mask,
456 std::string* kty,
457 std::string* actual_algorithm,
458 scoped_ptr<base::DictionaryValue>* dict) {
459 // Parse the incoming JWK JSON.
460 base::StringPiece json_string(reinterpret_cast<const char*>(bytes.bytes()),
461 bytes.byte_length());
462
463 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
464 base::DictionaryValue* dict_value = NULL;
465
466 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value)
467 return Status::ErrorJwkNotDictionary();
468
469 // Transfer to caller.
470 ignore_result(value.release());
Ryan Sleevi 2014/07/12 00:55:27 This needs more documentation, because I had serio
eroman 2014/07/12 01:59:30 Done.
471 dict->reset(dict_value);
472
473 // JWK "kty". Exit early if this required JWK parameter is missing.
474 Status status = GetJwkString(dict_value, "kty", kty);
475 if (status.IsError())
476 return status;
477
478 status = VerifyAlg(dict_value, expected_algorithm, actual_algorithm);
479 if (status.IsError())
480 return status;
481
482 status = VerifyExt(dict_value, expected_extractable);
483 if (status.IsError())
484 return status;
485
486 status = VerifyUsages(dict_value, expected_usage_mask);
487 if (status.IsError())
488 return status;
489
490 return Status::Success();
491 }
492
493 Status ReadSecretKeyJwkHelper(const CryptoData& key_data,
494 const std::string& expected_algorithm,
495 bool expected_extractable,
496 blink::WebCryptoKeyUsageMask expected_usage_mask,
497 std::string* actual_algorithm,
498 std::vector<uint8>* raw_key_data) {
499 if (!key_data.byte_length())
500 return Status::ErrorImportEmptyKeyData();
501
502 scoped_ptr<base::DictionaryValue> dict;
503 std::string kty;
504 Status status = ParseJwkCommon(key_data,
505 expected_algorithm,
506 expected_extractable,
507 expected_usage_mask,
508 &kty,
509 actual_algorithm,
510 &dict);
511 if (status.IsError())
512 return status;
513
514 if (kty != "oct")
515 return Status::ErrorJwkUnexpectedKty("oct");
516
517 std::string jwk_k_value;
518 status = GetJwkBytes(dict.get(), "k", &jwk_k_value);
519 if (status.IsError())
520 return status;
521 raw_key_data->assign(jwk_k_value.begin(), jwk_k_value.end());
522
523 return Status::Success();
524 }
525
526 } // namespace
527
528 void WriteSecretKeyJwk(const CryptoData& raw_key_data,
529 const std::string& algorithm,
530 bool extractable,
531 blink::WebCryptoKeyUsageMask usage_mask,
532 std::vector<uint8>* jwk_key_data) {
533 JwkWriter writer(algorithm, extractable, usage_mask, "oct");
534 writer.SetBase64Encoded("k", raw_key_data);
535 writer.ToBytes(jwk_key_data);
536 }
537
538 Status ReadSecretKeyJwk(const CryptoData& key_data,
539 const std::string& expected_algorithm,
540 bool expected_extractable,
541 blink::WebCryptoKeyUsageMask expected_usage_mask,
542 std::vector<uint8>* raw_key_data) {
543 return ReadSecretKeyJwkHelper(key_data,
544 expected_algorithm,
545 expected_extractable,
546 expected_usage_mask,
547 NULL,
548 raw_key_data);
549 }
550
551 std::string MakeJwkAesAlgorithmName(const std::string& suffix,
552 unsigned int keylen_bytes) {
553 if (keylen_bytes == 16)
554 return std::string("A128") + suffix;
555 if (keylen_bytes == 24)
556 return std::string("A192") + suffix;
557 if (keylen_bytes == 32)
558 return std::string("A256") + suffix;
559 return std::string();
560 }
561
562 Status ReadAesSecretKeyJwk(const CryptoData& key_data,
563 const std::string& algorithm_name_suffix,
564 bool expected_extractable,
565 blink::WebCryptoKeyUsageMask expected_usage_mask,
566 std::vector<uint8>* raw_key_data) {
567 std::string jwk_algorithm_name;
568 Status status = ReadSecretKeyJwkHelper(key_data,
569 "",
Ryan Sleevi 2014/07/12 00:55:27 std::string()
570 expected_extractable,
571 expected_usage_mask,
572 &jwk_algorithm_name,
573 raw_key_data);
574 if (status.IsError())
575 return status;
576
577 std::string expected_algorithm_name =
578 MakeJwkAesAlgorithmName(algorithm_name_suffix, raw_key_data->size());
579
580 if (!jwk_algorithm_name.empty() &&
581 jwk_algorithm_name != expected_algorithm_name) {
582 // Give a different error message if the key length was wrong.
583 if (jwk_algorithm_name ==
584 MakeJwkAesAlgorithmName(algorithm_name_suffix, 16) ||
585 jwk_algorithm_name ==
586 MakeJwkAesAlgorithmName(algorithm_name_suffix, 24) ||
587 jwk_algorithm_name ==
588 MakeJwkAesAlgorithmName(algorithm_name_suffix, 32)) {
Ryan Sleevi 2014/07/12 00:55:27 Doesn't this seem like it should be up to the impl
eroman 2014/07/12 01:59:30 Indeed. Initially I had the code as part of the im
940 return Status::ErrorJwkIncorrectKeyLength(); 589 return Status::ErrorJwkIncorrectKeyLength();
941 } 590 }
942 591 return Status::ErrorJwkAlgorithmInconsistent();
943 return ImportKey(blink::WebCryptoKeyFormatRaw, 592 }
944 CryptoData(jwk_k_value), 593
945 algorithm, 594 return Status::Success();
946 extractable, 595 }
947 usage_mask, 596
948 key); 597 // Writes an RSA public key to a JWK dictionary
949 } 598 void WriteRsaPublicKeyJwk(const CryptoData& n,
950 599 const CryptoData& e,
951 if (jwk_kty_value == "RSA") 600 const std::string& algorithm,
952 return ImportRsaKey(dict_value, algorithm, extractable, usage_mask, key); 601 bool extractable,
953 602 blink::WebCryptoKeyUsageMask usage_mask,
954 return Status::ErrorJwkUnrecognizedKty(); 603 std::vector<uint8>* jwk_key_data) {
955 } 604 JwkWriter writer(algorithm, extractable, usage_mask, "RSA");
956 605 writer.SetBase64Encoded("n", n);
957 Status ExportKeyJwk(const blink::WebCryptoKey& key, 606 writer.SetBase64Encoded("e", e);
958 std::vector<uint8>* buffer) { 607 writer.ToBytes(jwk_key_data);
959 DCHECK(key.extractable()); 608 }
960 base::DictionaryValue jwk_dict; 609
961 Status status = Status::OperationError(); 610 // Writes an RSA private key to a JWK dictionary
962 611 void WriteRsaPrivateKeyJwk(const CryptoData& n,
963 switch (key.type()) { 612 const CryptoData& e,
964 case blink::WebCryptoKeyTypeSecret: { 613 const CryptoData& d,
965 std::vector<uint8> exported_key; 614 const CryptoData& p,
966 status = ExportKey(blink::WebCryptoKeyFormatRaw, key, &exported_key); 615 const CryptoData& q,
967 if (status.IsError()) 616 const CryptoData& dp,
968 return status; 617 const CryptoData& dq,
969 WriteSecretKey(exported_key, &jwk_dict); 618 const CryptoData& qi,
970 break; 619 const std::string& algorithm,
971 } 620 bool extractable,
972 case blink::WebCryptoKeyTypePublic: { 621 blink::WebCryptoKeyUsageMask usage_mask,
973 // TODO(eroman): Update when there are asymmetric keys other than RSA. 622 std::vector<uint8>* jwk_key_data) {
974 if (!IsRsaKey(key)) 623 JwkWriter writer(algorithm, extractable, usage_mask, "RSA");
975 return Status::ErrorUnsupported(); 624
976 platform::PublicKey* public_key; 625 writer.SetBase64Encoded("n", n);
977 status = ToPlatformPublicKey(key, &public_key); 626 writer.SetBase64Encoded("e", e);
978 if (status.IsError()) 627 writer.SetBase64Encoded("d", d);
979 return status; 628 // Although these are "optional" in the JWA, WebCrypto spec requires them to
980 std::vector<uint8> modulus; 629 // be emitted.
981 std::vector<uint8> public_exponent; 630 writer.SetBase64Encoded("p", p);
982 status = 631 writer.SetBase64Encoded("q", q);
983 platform::ExportRsaPublicKey(public_key, &modulus, &public_exponent); 632 writer.SetBase64Encoded("dp", dp);
984 if (status.IsError()) 633 writer.SetBase64Encoded("dq", dq);
985 return status; 634 writer.SetBase64Encoded("qi", qi);
986 WriteRsaPublicKey(modulus, public_exponent, &jwk_dict); 635 writer.ToBytes(jwk_key_data);
987 break; 636 }
988 } 637
989 case blink::WebCryptoKeyTypePrivate: { 638 JwkRsaInfo::JwkRsaInfo() : is_private_key(false) {
990 // TODO(eroman): Update when there are asymmetric keys other than RSA. 639 }
991 if (!IsRsaKey(key)) 640
992 return Status::ErrorUnsupported(); 641 JwkRsaInfo::~JwkRsaInfo() {
993 642 }
994 status = ExportRsaPrivateKeyJwk(key, &jwk_dict); 643
995 if (status.IsError()) 644 Status ReadRsaKeyJwk(const CryptoData& key_data,
996 return status; 645 const std::string& expected_algorithm,
997 break; 646 bool expected_extractable,
998 } 647 blink::WebCryptoKeyUsageMask expected_usage_mask,
999 648 JwkRsaInfo* result) {
649 if (!key_data.byte_length())
650 return Status::ErrorImportEmptyKeyData();
651
652 scoped_ptr<base::DictionaryValue> dict;
653 std::string kty;
654 Status status = ParseJwkCommon(key_data,
655 expected_algorithm,
656 expected_extractable,
657 expected_usage_mask,
658 &kty,
659 NULL,
660 &dict);
661 if (status.IsError())
662 return status;
663
664 if (kty != "RSA")
665 return Status::ErrorJwkUnexpectedKty("RSA");
666
667 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
668 // in the JWK, while an RSA private key must have those, plus at least a "d"
669 // (private exponent) entry.
670 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
671 // section 6.3.
672 status = GetJwkBytes(dict.get(), "n", &result->n);
673 if (status.IsError())
674 return status;
675 status = GetJwkBytes(dict.get(), "e", &result->e);
676 if (status.IsError())
677 return status;
678
679 result->is_private_key = dict->HasKey("d");
680 if (!result->is_private_key)
681 return Status::Success();
682
683 status = GetJwkBytes(dict.get(), "d", &result->d);
684 if (status.IsError())
685 return status;
686
687 // The "p", "q", "dp", "dq", and "qi" properties are optional. Treat these
688 // properties the same if they are unspecified, as if they were specified-but
689 // empty, since ImportRsaPrivateKey() doesn't do validation checks anyway.
690
691 bool has_p;
692 status = GetOptionalJwkBytes(dict.get(), "p", &result->p, &has_p);
693 if (status.IsError())
694 return status;
695
696 bool has_q;
697 status = GetOptionalJwkBytes(dict.get(), "q", &result->q, &has_q);
698 if (status.IsError())
699 return status;
700
701 bool has_dp;
702 status = GetOptionalJwkBytes(dict.get(), "dp", &result->dp, &has_dp);
703 if (status.IsError())
704 return status;
705
706 bool has_dq;
707 status = GetOptionalJwkBytes(dict.get(), "dq", &result->dq, &has_dq);
708 if (status.IsError())
709 return status;
710
711 bool has_qi;
712 status = GetOptionalJwkBytes(dict.get(), "qi", &result->qi, &has_qi);
713 if (status.IsError())
714 return status;
715
716 int num_optional_properties = has_p + has_q + has_dp + has_dq + has_qi;
717 if (num_optional_properties != 0 && num_optional_properties != 5)
718 return Status::ErrorJwkIncompleteOptionalRsaPrivateKey();
719
720 return Status::Success();
721 }
722
723 const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) {
724 switch (hash) {
725 case blink::WebCryptoAlgorithmIdSha1:
726 return "HS1";
727 case blink::WebCryptoAlgorithmIdSha256:
728 return "HS256";
729 case blink::WebCryptoAlgorithmIdSha384:
730 return "HS384";
731 case blink::WebCryptoAlgorithmIdSha512:
732 return "HS512";
1000 default: 733 default:
1001 return Status::ErrorUnsupported(); 734 return NULL;
1002 } 735 }
1003
1004 WriteKeyOps(key.usages(), &jwk_dict);
1005 WriteExt(key.extractable(), &jwk_dict);
1006 status = WriteAlg(key.algorithm(), &jwk_dict);
1007 if (status.IsError())
1008 return status;
1009
1010 std::string json;
1011 base::JSONWriter::Write(&jwk_dict, &json);
1012 buffer->assign(json.data(), json.data() + json.size());
1013 return Status::Success();
1014 } 736 }
1015 737
1016 } // namespace webcrypto 738 } // namespace webcrypto
1017 739
1018 } // namespace content 740 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698