Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / child / webcrypto / jwk.cc
blob4bc15e2b788aa898ee618bbf31cb0bfba7cf3230
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
3 // found in the LICENSE file.
5 #include "jwk.h"
7 #include <algorithm>
8 #include <functional>
9 #include <map>
11 #include "base/json/json_reader.h"
12 #include "base/json/json_writer.h"
13 #include "base/strings/string_piece.h"
14 #include "content/child/webcrypto/crypto_data.h"
15 #include "content/child/webcrypto/status.h"
16 #include "content/child/webcrypto/webcrypto_util.h"
18 // TODO(eroman): The algorithm-specific logic in this file for AES and RSA
19 // should be moved into the corresponding AlgorithmImplementation file. It
20 // exists in this file to avoid duplication between OpenSSL and NSS
21 // implementations.
23 // JSON Web Key Format (JWK)
24 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-21
26 // A JWK is a simple JSON dictionary with the following entries
27 // - "kty" (Key Type) Parameter, REQUIRED
28 // - <kty-specific parameters, see below>, REQUIRED
29 // - "use" (Key Use) Parameter, OPTIONAL
30 // - "key_ops" (Key Operations) Parameter, OPTIONAL
31 // - "alg" (Algorithm) Parameter, OPTIONAL
32 // - "ext" (Key Exportability), OPTIONAL
33 // (all other entries are ignored)
35 // OPTIONAL here means that this code does not require the entry to be present
36 // in the incoming JWK, because the method input parameters contain similar
37 // information. If the optional JWK entry is present, it will be validated
38 // against the corresponding input parameter for consistency and combined with
39 // it according to rules defined below.
41 // Input 'key_data' contains the JWK. To build a Web Crypto Key, the JWK
42 // values are parsed out and combined with the method input parameters to
43 // build a Web Crypto Key:
44 // Web Crypto Key type <-- (deduced)
45 // Web Crypto Key extractable <-- JWK ext + input extractable
46 // Web Crypto Key algorithm <-- JWK alg + input algorithm
47 // Web Crypto Key keyUsage <-- JWK use, key_ops + input usage_mask
48 // Web Crypto Key keying material <-- kty-specific parameters
50 // Values for each JWK entry are case-sensitive and defined in
51 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18.
52 // Note that not all values specified by JOSE are handled by this code. Only
53 // handled values are listed.
54 // - kty (Key Type)
55 // +-------+--------------------------------------------------------------+
56 // | "RSA" | RSA [RFC3447] |
57 // | "oct" | Octet sequence (used to represent symmetric keys) |
58 // +-------+--------------------------------------------------------------+
60 // - key_ops (Key Use Details)
61 // The key_ops field is an array that contains one or more strings from
62 // the table below, and describes the operations for which this key may be
63 // used.
64 // +-------+--------------------------------------------------------------+
65 // | "encrypt" | encrypt operations |
66 // | "decrypt" | decrypt operations |
67 // | "sign" | sign (MAC) operations |
68 // | "verify" | verify (MAC) operations |
69 // | "wrapKey" | key wrap |
70 // | "unwrapKey" | key unwrap |
71 // | "deriveKey" | key derivation |
72 // | "deriveBits" | key derivation |
73 // +-------+--------------------------------------------------------------+
75 // - use (Key Use)
76 // The use field contains a single entry from the table below.
77 // +-------+--------------------------------------------------------------+
78 // | "sig" | equivalent to key_ops of [sign, verify] |
79 // | "enc" | equivalent to key_ops of [encrypt, decrypt, wrapKey, |
80 // | | unwrapKey, deriveKey, deriveBits] |
81 // +-------+--------------------------------------------------------------+
83 // NOTE: If both "use" and "key_ops" JWK members are present, the usages
84 // specified by them MUST be consistent. In particular, the "use" value
85 // "sig" corresponds to "sign" and/or "verify". The "use" value "enc"
86 // corresponds to all other values defined above. If "key_ops" values
87 // corresponding to both "sig" and "enc" "use" values are present, the "use"
88 // member SHOULD NOT be present, and if present, its value MUST NOT be
89 // either "sig" or "enc".
91 // - ext (Key Exportability)
92 // +-------+--------------------------------------------------------------+
93 // | true | Key may be exported from the trusted environment |
94 // | false | Key cannot exit the trusted environment |
95 // +-------+--------------------------------------------------------------+
97 // - alg (Algorithm)
98 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18
99 // +--------------+-------------------------------------------------------+
100 // | Digital Signature or MAC Algorithm |
101 // +--------------+-------------------------------------------------------+
102 // | "HS1" | HMAC using SHA-1 hash algorithm |
103 // | "HS256" | HMAC using SHA-256 hash algorithm |
104 // | "HS384" | HMAC using SHA-384 hash algorithm |
105 // | "HS512" | HMAC using SHA-512 hash algorithm |
106 // | "RS1" | RSASSA using SHA-1 hash algorithm
107 // | "RS256" | RSASSA using SHA-256 hash algorithm |
108 // | "RS384" | RSASSA using SHA-384 hash algorithm |
109 // | "RS512" | RSASSA using SHA-512 hash algorithm |
110 // +--------------+-------------------------------------------------------|
111 // | Key Management Algorithm |
112 // +--------------+-------------------------------------------------------+
113 // | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding |
114 // | | (OAEP) [RFC3447], with the default parameters |
115 // | | specified by RFC3447 in Section A.2.1 |
116 // | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm |
117 // | | [RFC3394] using 128 bit keys |
118 // | "A192KW" | AES Key Wrap Algorithm using 192 bit keys |
119 // | "A256KW" | AES Key Wrap Algorithm using 256 bit keys |
120 // | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using |
121 // | | 128 bit keys |
122 // | "A192GCM" | AES GCM using 192 bit keys |
123 // | "A256GCM" | AES GCM using 256 bit keys |
124 // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 |
125 // | | padding [NIST.800-38A] |
126 // | "A192CBC" | AES CBC using 192 bit keys |
127 // | "A256CBC" | AES CBC using 256 bit keys |
128 // +--------------+-------------------------------------------------------+
130 // kty-specific parameters
131 // The value of kty determines the type and content of the keying material
132 // carried in the JWK to be imported.
133 // // - kty == "oct" (symmetric or other raw key)
134 // +-------+--------------------------------------------------------------+
135 // | "k" | Contains the value of the symmetric (or other single-valued) |
136 // | | key. It is represented as the base64url encoding of the |
137 // | | octet sequence containing the key value. |
138 // +-------+--------------------------------------------------------------+
139 // - kty == "RSA" (RSA public key)
140 // +-------+--------------------------------------------------------------+
141 // | "n" | Contains the modulus value for the RSA public key. It is |
142 // | | represented as the base64url encoding of the value's |
143 // | | unsigned big endian representation as an octet sequence. |
144 // +-------+--------------------------------------------------------------+
145 // | "e" | Contains the exponent value for the RSA public key. It is |
146 // | | represented as the base64url encoding of the value's |
147 // | | unsigned big endian representation as an octet sequence. |
148 // +-------+--------------------------------------------------------------+
149 // - If key == "RSA" and the "d" parameter is present then it is a private key.
150 // All the parameters above for public keys apply, as well as the following.
151 // (Note that except for "d", all of these are optional):
152 // +-------+--------------------------------------------------------------+
153 // | "d" | Contains the private exponent value for the RSA private key. |
154 // | | It is represented as the base64url encoding of the value's |
155 // | | unsigned big endian representation as an octet sequence. |
156 // +-------+--------------------------------------------------------------+
157 // | "p" | Contains the first prime factor value for the RSA private |
158 // | | key. It is represented as the base64url encoding of the |
159 // | | value's |
160 // | | unsigned big endian representation as an octet sequence. |
161 // +-------+--------------------------------------------------------------+
162 // | "q" | Contains the second prime factor value for the RSA private |
163 // | | key. It is represented as the base64url encoding of the |
164 // | | value's unsigned big endian representation as an octet |
165 // | | sequence. |
166 // +-------+--------------------------------------------------------------+
167 // | "dp" | Contains the first factor CRT exponent value for the RSA |
168 // | | private key. It is represented as the base64url encoding of |
169 // | | the value's unsigned big endian representation as an octet |
170 // | | sequence. |
171 // +-------+--------------------------------------------------------------+
172 // | "dq" | Contains the second factor CRT exponent value for the RSA |
173 // | | private key. It is represented as the base64url encoding of |
174 // | | the value's unsigned big endian representation as an octet |
175 // | | sequence. |
176 // +-------+--------------------------------------------------------------+
177 // | "dq" | Contains the first CRT coefficient value for the RSA private |
178 // | | key. It is represented as the base64url encoding of the |
179 // | | value's unsigned big endian representation as an octet |
180 // | | sequence. |
181 // +-------+--------------------------------------------------------------+
183 // Consistency and conflict resolution
184 // The 'algorithm', 'extractable', and 'usage_mask' input parameters
185 // may be different than the corresponding values inside the JWK. The Web
186 // Crypto spec says that if a JWK value is present but is inconsistent with
187 // the input value, it is an error and the operation must fail. If no
188 // inconsistency is found then the input parameters are used.
190 // algorithm
191 // If the JWK algorithm is provided, it must match the web crypto input
192 // algorithm (both the algorithm ID and inner hash if applicable).
194 // extractable
195 // If the JWK ext field is true but the input parameter is false, make the
196 // Web Crypto Key non-extractable. Conversely, if the JWK ext field is
197 // false but the input parameter is true, it is an inconsistency. If both
198 // are true or both are false, use that value.
200 // usage_mask
201 // The input usage_mask must be a strict subset of the interpreted JWK use
202 // value, else it is judged inconsistent. In all cases the input usage_mask
203 // is used as the final usage_mask.
206 namespace content {
208 namespace webcrypto {
210 namespace {
212 // Web Crypto equivalent usage mask for JWK 'use' = 'enc'.
213 const blink::WebCryptoKeyUsageMask kJwkEncUsage =
214 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
215 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey |
216 blink::WebCryptoKeyUsageDeriveKey | blink::WebCryptoKeyUsageDeriveBits;
217 // Web Crypto equivalent usage mask for JWK 'use' = 'sig'.
218 const blink::WebCryptoKeyUsageMask kJwkSigUsage =
219 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
221 class JwkWriter {
222 public:
223 JwkWriter(const std::string& algorithm,
224 bool extractable,
225 blink::WebCryptoKeyUsageMask usage_mask,
226 const std::string& kty) {
227 dict_.SetString("alg", algorithm);
228 dict_.Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(usage_mask));
229 dict_.SetBoolean("ext", extractable);
230 dict_.SetString("kty", kty);
233 void Set(const std::string& key, const std::string& value) {
234 dict_.SetString(key, value);
237 void SetBase64Encoded(const std::string& key, const CryptoData& value) {
238 dict_.SetString(key,
239 Base64EncodeUrlSafe(base::StringPiece(
240 reinterpret_cast<const char*>(value.bytes()),
241 value.byte_length())));
244 void ToBytes(std::vector<uint8_t>* utf8_bytes) {
245 std::string json;
246 base::JSONWriter::Write(&dict_, &json);
247 utf8_bytes->assign(json.begin(), json.end());
250 private:
251 base::DictionaryValue dict_;
254 // Extracts the required string property with key |path| from |dict| and saves
255 // the result to |*result|. If the property does not exist or is not a string,
256 // returns an error.
257 Status GetJwkString(base::DictionaryValue* dict,
258 const std::string& path,
259 std::string* result) {
260 base::Value* value = NULL;
261 if (!dict->Get(path, &value))
262 return Status::ErrorJwkPropertyMissing(path);
263 if (!value->GetAsString(result))
264 return Status::ErrorJwkPropertyWrongType(path, "string");
265 return Status::Success();
268 // Extracts the optional string property with key |path| from |dict| and saves
269 // the result to |*result| if it was found. If the property exists and is not a
270 // string, returns an error. Otherwise returns success, and sets
271 // |*property_exists| if it was found.
272 Status GetOptionalJwkString(base::DictionaryValue* dict,
273 const std::string& path,
274 std::string* result,
275 bool* property_exists) {
276 *property_exists = false;
277 base::Value* value = NULL;
278 if (!dict->Get(path, &value))
279 return Status::Success();
281 if (!value->GetAsString(result))
282 return Status::ErrorJwkPropertyWrongType(path, "string");
284 *property_exists = true;
285 return Status::Success();
288 // Extracts the optional array property with key |path| from |dict| and saves
289 // the result to |*result| if it was found. If the property exists and is not an
290 // array, returns an error. Otherwise returns success, and sets
291 // |*property_exists| if it was found. Note that |*result| is owned by |dict|.
292 Status GetOptionalJwkList(base::DictionaryValue* dict,
293 const std::string& path,
294 base::ListValue** result,
295 bool* property_exists) {
296 *property_exists = false;
297 base::Value* value = NULL;
298 if (!dict->Get(path, &value))
299 return Status::Success();
301 if (!value->GetAsList(result))
302 return Status::ErrorJwkPropertyWrongType(path, "list");
304 *property_exists = true;
305 return Status::Success();
308 // Extracts the required string property with key |path| from |dict| and saves
309 // the base64url-decoded bytes to |*result|. If the property does not exist or
310 // is not a string, or could not be base64url-decoded, returns an error.
311 Status GetJwkBytes(base::DictionaryValue* dict,
312 const std::string& path,
313 std::string* result) {
314 std::string base64_string;
315 Status status = GetJwkString(dict, path, &base64_string);
316 if (status.IsError())
317 return status;
319 if (!Base64DecodeUrlSafe(base64_string, result))
320 return Status::ErrorJwkBase64Decode(path);
322 return Status::Success();
325 // Extracts the required base64url property, which is interpreted as being a
326 // big-endian unsigned integer.
327 Status GetJwkBigInteger(base::DictionaryValue* dict,
328 const std::string& path,
329 std::string* result) {
330 Status status = GetJwkBytes(dict, path, result);
331 if (status.IsError())
332 return status;
334 if (result->empty())
335 return Status::ErrorJwkEmptyBigInteger(path);
337 // The JWA spec says that "The octet sequence MUST utilize the minimum number
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);
343 return Status::Success();
346 // Extracts the optional boolean property with key |path| from |dict| and saves
347 // the result to |*result| if it was found. If the property exists and is not a
348 // boolean, returns an error. Otherwise returns success, and sets
349 // |*property_exists| if it was found.
350 Status GetOptionalJwkBool(base::DictionaryValue* dict,
351 const std::string& path,
352 bool* result,
353 bool* property_exists) {
354 *property_exists = false;
355 base::Value* value = NULL;
356 if (!dict->Get(path, &value))
357 return Status::Success();
359 if (!value->GetAsBoolean(result))
360 return Status::ErrorJwkPropertyWrongType(path, "boolean");
362 *property_exists = true;
363 return Status::Success();
366 Status VerifyExt(base::DictionaryValue* dict, bool expected_extractable) {
367 // JWK "ext" (optional) --> extractable parameter
368 bool jwk_ext_value = false;
369 bool has_jwk_ext;
370 Status status = GetOptionalJwkBool(dict, "ext", &jwk_ext_value, &has_jwk_ext);
371 if (status.IsError())
372 return status;
373 if (has_jwk_ext && expected_extractable && !jwk_ext_value)
374 return Status::ErrorJwkExtInconsistent();
375 return Status::Success();
378 Status VerifyUsages(base::DictionaryValue* dict,
379 blink::WebCryptoKeyUsageMask expected_usage_mask) {
380 // JWK "key_ops" (optional) --> usage_mask parameter
381 base::ListValue* jwk_key_ops_value = NULL;
382 bool has_jwk_key_ops;
383 Status status =
384 GetOptionalJwkList(dict, "key_ops", &jwk_key_ops_value, &has_jwk_key_ops);
385 if (status.IsError())
386 return status;
387 blink::WebCryptoKeyUsageMask jwk_key_ops_mask = 0;
388 if (has_jwk_key_ops) {
389 status =
390 GetWebCryptoUsagesFromJwkKeyOps(jwk_key_ops_value, &jwk_key_ops_mask);
391 if (status.IsError())
392 return status;
393 // The input usage_mask must be a subset of jwk_key_ops_mask.
394 if (!ContainsKeyUsages(jwk_key_ops_mask, expected_usage_mask))
395 return Status::ErrorJwkKeyopsInconsistent();
398 // JWK "use" (optional) --> usage_mask parameter
399 std::string jwk_use_value;
400 bool has_jwk_use;
401 status = GetOptionalJwkString(dict, "use", &jwk_use_value, &has_jwk_use);
402 if (status.IsError())
403 return status;
404 blink::WebCryptoKeyUsageMask jwk_use_mask = 0;
405 if (has_jwk_use) {
406 if (jwk_use_value == "enc")
407 jwk_use_mask = kJwkEncUsage;
408 else if (jwk_use_value == "sig")
409 jwk_use_mask = kJwkSigUsage;
410 else
411 return Status::ErrorJwkUnrecognizedUse();
412 // The input usage_mask must be a subset of jwk_use_mask.
413 if (!ContainsKeyUsages(jwk_use_mask, expected_usage_mask))
414 return Status::ErrorJwkUseInconsistent();
417 // If both 'key_ops' and 'use' are present, ensure they are consistent.
418 if (has_jwk_key_ops && has_jwk_use &&
419 !ContainsKeyUsages(jwk_use_mask, jwk_key_ops_mask))
420 return Status::ErrorJwkUseAndKeyopsInconsistent();
422 return Status::Success();
425 Status VerifyAlg(base::DictionaryValue* dict,
426 const std::string& expected_algorithm) {
427 // JWK "alg" --> algorithm parameter
428 bool has_jwk_alg;
429 std::string jwk_alg_value;
430 Status status =
431 GetOptionalJwkString(dict, "alg", &jwk_alg_value, &has_jwk_alg);
432 if (status.IsError())
433 return status;
435 if (has_jwk_alg && jwk_alg_value != expected_algorithm)
436 return Status::ErrorJwkAlgorithmInconsistent();
438 return Status::Success();
441 Status ParseJwkCommon(const CryptoData& bytes,
442 bool expected_extractable,
443 blink::WebCryptoKeyUsageMask expected_usage_mask,
444 std::string* kty,
445 scoped_ptr<base::DictionaryValue>* dict) {
446 // Parse the incoming JWK JSON.
447 base::StringPiece json_string(reinterpret_cast<const char*>(bytes.bytes()),
448 bytes.byte_length());
450 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
451 base::DictionaryValue* dict_value = NULL;
453 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value)
454 return Status::ErrorJwkNotDictionary();
456 // Release |value|, as ownership will be transferred to |dict| via
457 // |dict_value|, which points to the same object as |value|.
458 ignore_result(value.release());
459 dict->reset(dict_value);
461 // JWK "kty". Exit early if this required JWK parameter is missing.
462 Status status = GetJwkString(dict_value, "kty", kty);
463 if (status.IsError())
464 return status;
466 status = VerifyExt(dict_value, expected_extractable);
467 if (status.IsError())
468 return status;
470 status = VerifyUsages(dict_value, expected_usage_mask);
471 if (status.IsError())
472 return status;
474 return Status::Success();
477 Status ReadSecretKeyNoExpectedAlg(
478 const CryptoData& key_data,
479 bool expected_extractable,
480 blink::WebCryptoKeyUsageMask expected_usage_mask,
481 std::vector<uint8_t>* raw_key_data,
482 scoped_ptr<base::DictionaryValue>* dict) {
483 if (!key_data.byte_length())
484 return Status::ErrorImportEmptyKeyData();
486 std::string kty;
487 Status status = ParseJwkCommon(
488 key_data, expected_extractable, expected_usage_mask, &kty, dict);
489 if (status.IsError())
490 return status;
492 if (kty != "oct")
493 return Status::ErrorJwkUnexpectedKty("oct");
495 std::string jwk_k_value;
496 status = GetJwkBytes(dict->get(), "k", &jwk_k_value);
497 if (status.IsError())
498 return status;
499 raw_key_data->assign(jwk_k_value.begin(), jwk_k_value.end());
501 return Status::Success();
504 } // namespace
506 void WriteSecretKeyJwk(const CryptoData& raw_key_data,
507 const std::string& algorithm,
508 bool extractable,
509 blink::WebCryptoKeyUsageMask usage_mask,
510 std::vector<uint8_t>* jwk_key_data) {
511 JwkWriter writer(algorithm, extractable, usage_mask, "oct");
512 writer.SetBase64Encoded("k", raw_key_data);
513 writer.ToBytes(jwk_key_data);
516 Status ReadSecretKeyJwk(const CryptoData& key_data,
517 const std::string& expected_algorithm,
518 bool expected_extractable,
519 blink::WebCryptoKeyUsageMask expected_usage_mask,
520 std::vector<uint8_t>* raw_key_data) {
521 scoped_ptr<base::DictionaryValue> dict;
522 Status status = ReadSecretKeyNoExpectedAlg(
523 key_data, expected_extractable, expected_usage_mask, raw_key_data, &dict);
524 if (status.IsError())
525 return status;
526 return VerifyAlg(dict.get(), expected_algorithm);
529 std::string MakeJwkAesAlgorithmName(const std::string& suffix,
530 unsigned int keylen_bytes) {
531 if (keylen_bytes == 16)
532 return std::string("A128") + suffix;
533 if (keylen_bytes == 24)
534 return std::string("A192") + suffix;
535 if (keylen_bytes == 32)
536 return std::string("A256") + suffix;
537 return std::string();
540 Status ReadAesSecretKeyJwk(const CryptoData& key_data,
541 const std::string& algorithm_name_suffix,
542 bool expected_extractable,
543 blink::WebCryptoKeyUsageMask expected_usage_mask,
544 std::vector<uint8_t>* raw_key_data) {
545 scoped_ptr<base::DictionaryValue> dict;
546 Status status = ReadSecretKeyNoExpectedAlg(
547 key_data, expected_extractable, expected_usage_mask, raw_key_data, &dict);
548 if (status.IsError())
549 return status;
551 bool has_jwk_alg;
552 std::string jwk_alg;
553 status = GetOptionalJwkString(dict.get(), "alg", &jwk_alg, &has_jwk_alg);
554 if (status.IsError())
555 return status;
557 if (has_jwk_alg) {
558 std::string expected_algorithm_name =
559 MakeJwkAesAlgorithmName(algorithm_name_suffix, raw_key_data->size());
561 if (jwk_alg != expected_algorithm_name) {
562 // Give a different error message if the key length was wrong.
563 if (jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 16) ||
564 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 24) ||
565 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 32)) {
566 return Status::ErrorJwkIncorrectKeyLength();
568 return Status::ErrorJwkAlgorithmInconsistent();
572 return Status::Success();
575 // Writes an RSA public key to a JWK dictionary
576 void WriteRsaPublicKeyJwk(const CryptoData& n,
577 const CryptoData& e,
578 const std::string& algorithm,
579 bool extractable,
580 blink::WebCryptoKeyUsageMask usage_mask,
581 std::vector<uint8_t>* jwk_key_data) {
582 JwkWriter writer(algorithm, extractable, usage_mask, "RSA");
583 writer.SetBase64Encoded("n", n);
584 writer.SetBase64Encoded("e", e);
585 writer.ToBytes(jwk_key_data);
588 // Writes an RSA private key to a JWK dictionary
589 void WriteRsaPrivateKeyJwk(const CryptoData& n,
590 const CryptoData& e,
591 const CryptoData& d,
592 const CryptoData& p,
593 const CryptoData& q,
594 const CryptoData& dp,
595 const CryptoData& dq,
596 const CryptoData& qi,
597 const std::string& algorithm,
598 bool extractable,
599 blink::WebCryptoKeyUsageMask usage_mask,
600 std::vector<uint8_t>* jwk_key_data) {
601 JwkWriter writer(algorithm, extractable, usage_mask, "RSA");
603 writer.SetBase64Encoded("n", n);
604 writer.SetBase64Encoded("e", e);
605 writer.SetBase64Encoded("d", d);
606 // Although these are "optional" in the JWA, WebCrypto spec requires them to
607 // be emitted.
608 writer.SetBase64Encoded("p", p);
609 writer.SetBase64Encoded("q", q);
610 writer.SetBase64Encoded("dp", dp);
611 writer.SetBase64Encoded("dq", dq);
612 writer.SetBase64Encoded("qi", qi);
613 writer.ToBytes(jwk_key_data);
616 JwkRsaInfo::JwkRsaInfo() : is_private_key(false) {
619 JwkRsaInfo::~JwkRsaInfo() {
622 Status ReadRsaKeyJwk(const CryptoData& key_data,
623 const std::string& expected_algorithm,
624 bool expected_extractable,
625 blink::WebCryptoKeyUsageMask expected_usage_mask,
626 JwkRsaInfo* result) {
627 if (!key_data.byte_length())
628 return Status::ErrorImportEmptyKeyData();
630 scoped_ptr<base::DictionaryValue> dict;
631 std::string kty;
632 Status status = ParseJwkCommon(
633 key_data, expected_extractable, expected_usage_mask, &kty, &dict);
634 if (status.IsError())
635 return status;
637 status = VerifyAlg(dict.get(), expected_algorithm);
638 if (status.IsError())
639 return status;
641 if (kty != "RSA")
642 return Status::ErrorJwkUnexpectedKty("RSA");
644 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
645 // in the JWK, while an RSA private key must have those, plus at least a "d"
646 // (private exponent) entry.
647 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
648 // section 6.3.
649 status = GetJwkBigInteger(dict.get(), "n", &result->n);
650 if (status.IsError())
651 return status;
652 status = GetJwkBigInteger(dict.get(), "e", &result->e);
653 if (status.IsError())
654 return status;
656 result->is_private_key = dict->HasKey("d");
657 if (!result->is_private_key)
658 return Status::Success();
660 status = GetJwkBigInteger(dict.get(), "d", &result->d);
661 if (status.IsError())
662 return status;
664 // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA
665 // spec. However they are required by Chromium's WebCrypto implementation.
667 status = GetJwkBigInteger(dict.get(), "p", &result->p);
668 if (status.IsError())
669 return status;
671 status = GetJwkBigInteger(dict.get(), "q", &result->q);
672 if (status.IsError())
673 return status;
675 status = GetJwkBigInteger(dict.get(), "dp", &result->dp);
676 if (status.IsError())
677 return status;
679 status = GetJwkBigInteger(dict.get(), "dq", &result->dq);
680 if (status.IsError())
681 return status;
683 status = GetJwkBigInteger(dict.get(), "qi", &result->qi);
684 if (status.IsError())
685 return status;
687 return Status::Success();
690 const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) {
691 switch (hash) {
692 case blink::WebCryptoAlgorithmIdSha1:
693 return "HS1";
694 case blink::WebCryptoAlgorithmIdSha256:
695 return "HS256";
696 case blink::WebCryptoAlgorithmIdSha384:
697 return "HS384";
698 case blink::WebCryptoAlgorithmIdSha512:
699 return "HS512";
700 default:
701 return NULL;
705 } // namespace webcrypto
707 } // namespace content