Removing uses of X11 native key events.
[chromium-blink-merge.git] / content / child / webcrypto / jwk.cc
blobe1ac96f409809a6dc4d79adcaf7453a02735ca76
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/base64.h"
12 #include "base/json/json_reader.h"
13 #include "base/json/json_writer.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string_piece.h"
16 #include "content/child/webcrypto/crypto_data.h"
17 #include "content/child/webcrypto/status.h"
18 #include "content/child/webcrypto/webcrypto_util.h"
20 // TODO(eroman): The algorithm-specific logic in this file for AES and RSA
21 // should be moved into the corresponding AlgorithmImplementation file. It
22 // exists in this file to avoid duplication between OpenSSL and NSS
23 // implementations.
25 // JSON Web Key Format (JWK)
26 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-21
28 // A JWK is a simple JSON dictionary with the following entries
29 // - "kty" (Key Type) Parameter, REQUIRED
30 // - <kty-specific parameters, see below>, REQUIRED
31 // - "use" (Key Use) Parameter, OPTIONAL
32 // - "key_ops" (Key Operations) Parameter, OPTIONAL
33 // - "alg" (Algorithm) Parameter, OPTIONAL
34 // - "ext" (Key Exportability), OPTIONAL
35 // (all other entries are ignored)
37 // OPTIONAL here means that this code does not require the entry to be present
38 // in the incoming JWK, because the method input parameters contain similar
39 // information. If the optional JWK entry is present, it will be validated
40 // against the corresponding input parameter for consistency and combined with
41 // it according to rules defined below.
43 // Input 'key_data' contains the JWK. To build a Web Crypto Key, the JWK
44 // values are parsed out and combined with the method input parameters to
45 // build a Web Crypto Key:
46 // Web Crypto Key type <-- (deduced)
47 // Web Crypto Key extractable <-- JWK ext + input extractable
48 // Web Crypto Key algorithm <-- JWK alg + input algorithm
49 // Web Crypto Key keyUsage <-- JWK use, key_ops + input usage_mask
50 // Web Crypto Key keying material <-- kty-specific parameters
52 // Values for each JWK entry are case-sensitive and defined in
53 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18.
54 // Note that not all values specified by JOSE are handled by this code. Only
55 // handled values are listed.
56 // - kty (Key Type)
57 // +-------+--------------------------------------------------------------+
58 // | "RSA" | RSA [RFC3447] |
59 // | "oct" | Octet sequence (used to represent symmetric keys) |
60 // +-------+--------------------------------------------------------------+
62 // - key_ops (Key Use Details)
63 // The key_ops field is an array that contains one or more strings from
64 // the table below, and describes the operations for which this key may be
65 // used.
66 // +-------+--------------------------------------------------------------+
67 // | "encrypt" | encrypt operations |
68 // | "decrypt" | decrypt operations |
69 // | "sign" | sign (MAC) operations |
70 // | "verify" | verify (MAC) operations |
71 // | "wrapKey" | key wrap |
72 // | "unwrapKey" | key unwrap |
73 // | "deriveKey" | key derivation |
74 // | "deriveBits" | key derivation |
75 // +-------+--------------------------------------------------------------+
77 // - use (Key Use)
78 // The use field contains a single entry from the table below.
79 // +-------+--------------------------------------------------------------+
80 // | "sig" | equivalent to key_ops of [sign, verify] |
81 // | "enc" | equivalent to key_ops of [encrypt, decrypt, wrapKey, |
82 // | | unwrapKey, deriveKey, deriveBits] |
83 // +-------+--------------------------------------------------------------+
85 // NOTE: If both "use" and "key_ops" JWK members are present, the usages
86 // specified by them MUST be consistent. In particular, the "use" value
87 // "sig" corresponds to "sign" and/or "verify". The "use" value "enc"
88 // corresponds to all other values defined above. If "key_ops" values
89 // corresponding to both "sig" and "enc" "use" values are present, the "use"
90 // member SHOULD NOT be present, and if present, its value MUST NOT be
91 // either "sig" or "enc".
93 // - ext (Key Exportability)
94 // +-------+--------------------------------------------------------------+
95 // | true | Key may be exported from the trusted environment |
96 // | false | Key cannot exit the trusted environment |
97 // +-------+--------------------------------------------------------------+
99 // - alg (Algorithm)
100 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18
101 // +--------------+-------------------------------------------------------+
102 // | Digital Signature or MAC Algorithm |
103 // +--------------+-------------------------------------------------------+
104 // | "HS1" | HMAC using SHA-1 hash algorithm |
105 // | "HS256" | HMAC using SHA-256 hash algorithm |
106 // | "HS384" | HMAC using SHA-384 hash algorithm |
107 // | "HS512" | HMAC using SHA-512 hash algorithm |
108 // | "RS1" | RSASSA using SHA-1 hash algorithm
109 // | "RS256" | RSASSA using SHA-256 hash algorithm |
110 // | "RS384" | RSASSA using SHA-384 hash algorithm |
111 // | "RS512" | RSASSA using SHA-512 hash algorithm |
112 // +--------------+-------------------------------------------------------|
113 // | Key Management Algorithm |
114 // +--------------+-------------------------------------------------------+
115 // | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding |
116 // | | (OAEP) [RFC3447], with the default parameters |
117 // | | specified by RFC3447 in Section A.2.1 |
118 // | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm |
119 // | | [RFC3394] using 128 bit keys |
120 // | "A192KW" | AES Key Wrap Algorithm using 192 bit keys |
121 // | "A256KW" | AES Key Wrap Algorithm using 256 bit keys |
122 // | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using |
123 // | | 128 bit keys |
124 // | "A192GCM" | AES GCM using 192 bit keys |
125 // | "A256GCM" | AES GCM using 256 bit keys |
126 // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 |
127 // | | padding [NIST.800-38A] |
128 // | "A192CBC" | AES CBC using 192 bit keys |
129 // | "A256CBC" | AES CBC using 256 bit keys |
130 // +--------------+-------------------------------------------------------+
132 // kty-specific parameters
133 // The value of kty determines the type and content of the keying material
134 // carried in the JWK to be imported.
135 // // - kty == "oct" (symmetric or other raw key)
136 // +-------+--------------------------------------------------------------+
137 // | "k" | Contains the value of the symmetric (or other single-valued) |
138 // | | key. It is represented as the base64url encoding of the |
139 // | | octet sequence containing the key value. |
140 // +-------+--------------------------------------------------------------+
141 // - kty == "RSA" (RSA public key)
142 // +-------+--------------------------------------------------------------+
143 // | "n" | Contains the modulus value for the RSA public key. It is |
144 // | | represented as the base64url encoding of the value's |
145 // | | unsigned big endian representation as an octet sequence. |
146 // +-------+--------------------------------------------------------------+
147 // | "e" | Contains the exponent value for the RSA public key. It is |
148 // | | represented as the base64url encoding of the value's |
149 // | | unsigned big endian representation as an octet sequence. |
150 // +-------+--------------------------------------------------------------+
151 // - If key == "RSA" and the "d" parameter is present then it is a private key.
152 // All the parameters above for public keys apply, as well as the following.
153 // (Note that except for "d", all of these are optional):
154 // +-------+--------------------------------------------------------------+
155 // | "d" | Contains the private exponent value for the RSA private key. |
156 // | | It is represented as the base64url encoding of the value's |
157 // | | unsigned big endian representation as an octet sequence. |
158 // +-------+--------------------------------------------------------------+
159 // | "p" | Contains the first prime factor value for the RSA private |
160 // | | key. It is represented as the base64url encoding of the |
161 // | | value's |
162 // | | unsigned big endian representation as an octet sequence. |
163 // +-------+--------------------------------------------------------------+
164 // | "q" | Contains the second prime factor value for the RSA private |
165 // | | key. It is represented as the base64url encoding of the |
166 // | | value's unsigned big endian representation as an octet |
167 // | | sequence. |
168 // +-------+--------------------------------------------------------------+
169 // | "dp" | Contains the first factor CRT exponent value for the RSA |
170 // | | private key. It is represented as the base64url encoding of |
171 // | | the value's unsigned big endian representation as an octet |
172 // | | sequence. |
173 // +-------+--------------------------------------------------------------+
174 // | "dq" | Contains the second factor CRT exponent value for the RSA |
175 // | | private key. It is represented as the base64url encoding of |
176 // | | the value's unsigned big endian representation as an octet |
177 // | | sequence. |
178 // +-------+--------------------------------------------------------------+
179 // | "dq" | Contains the first CRT coefficient value for the RSA private |
180 // | | key. It is represented as the base64url encoding of the |
181 // | | value's unsigned big endian representation as an octet |
182 // | | sequence. |
183 // +-------+--------------------------------------------------------------+
185 // Consistency and conflict resolution
186 // The 'algorithm', 'extractable', and 'usage_mask' input parameters
187 // may be different than the corresponding values inside the JWK. The Web
188 // Crypto spec says that if a JWK value is present but is inconsistent with
189 // the input value, it is an error and the operation must fail. If no
190 // inconsistency is found then the input parameters are used.
192 // algorithm
193 // If the JWK algorithm is provided, it must match the web crypto input
194 // algorithm (both the algorithm ID and inner hash if applicable).
196 // extractable
197 // If the JWK ext field is true but the input parameter is false, make the
198 // Web Crypto Key non-extractable. Conversely, if the JWK ext field is
199 // false but the input parameter is true, it is an inconsistency. If both
200 // are true or both are false, use that value.
202 // usage_mask
203 // The input usage_mask must be a strict subset of the interpreted JWK use
204 // value, else it is judged inconsistent. In all cases the input usage_mask
205 // is used as the final usage_mask.
208 namespace content {
210 namespace webcrypto {
212 namespace {
214 // Web Crypto equivalent usage mask for JWK 'use' = 'enc'.
215 const blink::WebCryptoKeyUsageMask kJwkEncUsage =
216 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
217 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey |
218 blink::WebCryptoKeyUsageDeriveKey | blink::WebCryptoKeyUsageDeriveBits;
219 // Web Crypto equivalent usage mask for JWK 'use' = 'sig'.
220 const blink::WebCryptoKeyUsageMask kJwkSigUsage =
221 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
223 class JwkWriter {
224 public:
225 JwkWriter(const std::string& algorithm,
226 bool extractable,
227 blink::WebCryptoKeyUsageMask usage_mask,
228 const std::string& kty) {
229 dict_.SetString("alg", algorithm);
230 dict_.Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(usage_mask));
231 dict_.SetBoolean("ext", extractable);
232 dict_.SetString("kty", kty);
235 void Set(const std::string& key, const std::string& value) {
236 dict_.SetString(key, value);
239 void SetBase64Encoded(const std::string& key, const CryptoData& value) {
240 dict_.SetString(key,
241 Base64EncodeUrlSafe(base::StringPiece(
242 reinterpret_cast<const char*>(value.bytes()),
243 value.byte_length())));
246 void ToBytes(std::vector<uint8_t>* utf8_bytes) {
247 std::string json;
248 base::JSONWriter::Write(&dict_, &json);
249 utf8_bytes->assign(json.begin(), json.end());
252 private:
253 base::DictionaryValue dict_;
256 // Extracts the required string property with key |path| from |dict| and saves
257 // the result to |*result|. If the property does not exist or is not a string,
258 // returns an error.
259 Status GetJwkString(base::DictionaryValue* dict,
260 const std::string& path,
261 std::string* result) {
262 base::Value* value = NULL;
263 if (!dict->Get(path, &value))
264 return Status::ErrorJwkPropertyMissing(path);
265 if (!value->GetAsString(result))
266 return Status::ErrorJwkPropertyWrongType(path, "string");
267 return Status::Success();
270 // Extracts the optional string property with key |path| from |dict| and saves
271 // the result to |*result| if it was found. If the property exists and is not a
272 // string, returns an error. Otherwise returns success, and sets
273 // |*property_exists| if it was found.
274 Status GetOptionalJwkString(base::DictionaryValue* dict,
275 const std::string& path,
276 std::string* result,
277 bool* property_exists) {
278 *property_exists = false;
279 base::Value* value = NULL;
280 if (!dict->Get(path, &value))
281 return Status::Success();
283 if (!value->GetAsString(result))
284 return Status::ErrorJwkPropertyWrongType(path, "string");
286 *property_exists = true;
287 return Status::Success();
290 // Extracts the optional array property with key |path| from |dict| and saves
291 // the result to |*result| if it was found. If the property exists and is not an
292 // array, returns an error. Otherwise returns success, and sets
293 // |*property_exists| if it was found. Note that |*result| is owned by |dict|.
294 Status GetOptionalJwkList(base::DictionaryValue* dict,
295 const std::string& path,
296 base::ListValue** result,
297 bool* property_exists) {
298 *property_exists = false;
299 base::Value* value = NULL;
300 if (!dict->Get(path, &value))
301 return Status::Success();
303 if (!value->GetAsList(result))
304 return Status::ErrorJwkPropertyWrongType(path, "list");
306 *property_exists = true;
307 return Status::Success();
310 // Extracts the required string property with key |path| from |dict| and saves
311 // the base64url-decoded bytes to |*result|. If the property does not exist or
312 // is not a string, or could not be base64url-decoded, returns an error.
313 Status GetJwkBytes(base::DictionaryValue* dict,
314 const std::string& path,
315 std::string* result) {
316 std::string base64_string;
317 Status status = GetJwkString(dict, path, &base64_string);
318 if (status.IsError())
319 return status;
321 if (!Base64DecodeUrlSafe(base64_string, result))
322 return Status::ErrorJwkBase64Decode(path);
324 return Status::Success();
327 // Extracts the required base64url property, which is interpreted as being a
328 // big-endian unsigned integer.
329 Status GetJwkBigInteger(base::DictionaryValue* dict,
330 const std::string& path,
331 std::string* result) {
332 Status status = GetJwkBytes(dict, path, result);
333 if (status.IsError())
334 return status;
336 if (result->empty())
337 return Status::ErrorJwkEmptyBigInteger(path);
339 // The JWA spec says that "The octet sequence MUST utilize the minimum number
340 // of octets to represent the value." This means there shouldn't be any
341 // leading zeros.
342 if (result->size() > 1 && (*result)[0] == 0)
343 return Status::ErrorJwkBigIntegerHasLeadingZero(path);
345 return Status::Success();
348 // Extracts the optional boolean property with key |path| from |dict| and saves
349 // the result to |*result| if it was found. If the property exists and is not a
350 // boolean, returns an error. Otherwise returns success, and sets
351 // |*property_exists| if it was found.
352 Status GetOptionalJwkBool(base::DictionaryValue* dict,
353 const std::string& path,
354 bool* result,
355 bool* property_exists) {
356 *property_exists = false;
357 base::Value* value = NULL;
358 if (!dict->Get(path, &value))
359 return Status::Success();
361 if (!value->GetAsBoolean(result))
362 return Status::ErrorJwkPropertyWrongType(path, "boolean");
364 *property_exists = true;
365 return Status::Success();
368 Status VerifyExt(base::DictionaryValue* dict, bool expected_extractable) {
369 // JWK "ext" (optional) --> extractable parameter
370 bool jwk_ext_value = false;
371 bool has_jwk_ext;
372 Status status = GetOptionalJwkBool(dict, "ext", &jwk_ext_value, &has_jwk_ext);
373 if (status.IsError())
374 return status;
375 if (has_jwk_ext && expected_extractable && !jwk_ext_value)
376 return Status::ErrorJwkExtInconsistent();
377 return Status::Success();
380 Status VerifyUsages(base::DictionaryValue* dict,
381 blink::WebCryptoKeyUsageMask expected_usage_mask) {
382 // JWK "key_ops" (optional) --> usage_mask parameter
383 base::ListValue* jwk_key_ops_value = NULL;
384 bool has_jwk_key_ops;
385 Status status =
386 GetOptionalJwkList(dict, "key_ops", &jwk_key_ops_value, &has_jwk_key_ops);
387 if (status.IsError())
388 return status;
389 blink::WebCryptoKeyUsageMask jwk_key_ops_mask = 0;
390 if (has_jwk_key_ops) {
391 status =
392 GetWebCryptoUsagesFromJwkKeyOps(jwk_key_ops_value, &jwk_key_ops_mask);
393 if (status.IsError())
394 return status;
395 // The input usage_mask must be a subset of jwk_key_ops_mask.
396 if (!ContainsKeyUsages(jwk_key_ops_mask, expected_usage_mask))
397 return Status::ErrorJwkKeyopsInconsistent();
400 // JWK "use" (optional) --> usage_mask parameter
401 std::string jwk_use_value;
402 bool has_jwk_use;
403 status = GetOptionalJwkString(dict, "use", &jwk_use_value, &has_jwk_use);
404 if (status.IsError())
405 return status;
406 blink::WebCryptoKeyUsageMask jwk_use_mask = 0;
407 if (has_jwk_use) {
408 if (jwk_use_value == "enc")
409 jwk_use_mask = kJwkEncUsage;
410 else if (jwk_use_value == "sig")
411 jwk_use_mask = kJwkSigUsage;
412 else
413 return Status::ErrorJwkUnrecognizedUse();
414 // The input usage_mask must be a subset of jwk_use_mask.
415 if (!ContainsKeyUsages(jwk_use_mask, expected_usage_mask))
416 return Status::ErrorJwkUseInconsistent();
419 // If both 'key_ops' and 'use' are present, ensure they are consistent.
420 if (has_jwk_key_ops && has_jwk_use &&
421 !ContainsKeyUsages(jwk_use_mask, jwk_key_ops_mask))
422 return Status::ErrorJwkUseAndKeyopsInconsistent();
424 return Status::Success();
427 Status VerifyAlg(base::DictionaryValue* dict,
428 const std::string& expected_algorithm) {
429 // JWK "alg" --> algorithm parameter
430 bool has_jwk_alg;
431 std::string jwk_alg_value;
432 Status status =
433 GetOptionalJwkString(dict, "alg", &jwk_alg_value, &has_jwk_alg);
434 if (status.IsError())
435 return status;
437 if (has_jwk_alg && jwk_alg_value != expected_algorithm)
438 return Status::ErrorJwkAlgorithmInconsistent();
440 return Status::Success();
443 Status ParseJwkCommon(const CryptoData& bytes,
444 bool expected_extractable,
445 blink::WebCryptoKeyUsageMask expected_usage_mask,
446 std::string* kty,
447 scoped_ptr<base::DictionaryValue>* dict) {
448 // Parse the incoming JWK JSON.
449 base::StringPiece json_string(reinterpret_cast<const char*>(bytes.bytes()),
450 bytes.byte_length());
452 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
453 base::DictionaryValue* dict_value = NULL;
455 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value)
456 return Status::ErrorJwkNotDictionary();
458 // Release |value|, as ownership will be transferred to |dict| via
459 // |dict_value|, which points to the same object as |value|.
460 ignore_result(value.release());
461 dict->reset(dict_value);
463 // JWK "kty". Exit early if this required JWK parameter is missing.
464 Status status = GetJwkString(dict_value, "kty", kty);
465 if (status.IsError())
466 return status;
468 status = VerifyExt(dict_value, expected_extractable);
469 if (status.IsError())
470 return status;
472 status = VerifyUsages(dict_value, expected_usage_mask);
473 if (status.IsError())
474 return status;
476 return Status::Success();
479 Status ReadSecretKeyNoExpectedAlg(
480 const CryptoData& key_data,
481 bool expected_extractable,
482 blink::WebCryptoKeyUsageMask expected_usage_mask,
483 std::vector<uint8_t>* raw_key_data,
484 scoped_ptr<base::DictionaryValue>* dict) {
485 if (!key_data.byte_length())
486 return Status::ErrorImportEmptyKeyData();
488 std::string kty;
489 Status status = ParseJwkCommon(
490 key_data, expected_extractable, expected_usage_mask, &kty, dict);
491 if (status.IsError())
492 return status;
494 if (kty != "oct")
495 return Status::ErrorJwkUnexpectedKty("oct");
497 std::string jwk_k_value;
498 status = GetJwkBytes(dict->get(), "k", &jwk_k_value);
499 if (status.IsError())
500 return status;
501 raw_key_data->assign(jwk_k_value.begin(), jwk_k_value.end());
503 return Status::Success();
506 } // namespace
508 void WriteSecretKeyJwk(const CryptoData& raw_key_data,
509 const std::string& algorithm,
510 bool extractable,
511 blink::WebCryptoKeyUsageMask usage_mask,
512 std::vector<uint8_t>* jwk_key_data) {
513 JwkWriter writer(algorithm, extractable, usage_mask, "oct");
514 writer.SetBase64Encoded("k", raw_key_data);
515 writer.ToBytes(jwk_key_data);
518 Status ReadSecretKeyJwk(const CryptoData& key_data,
519 const std::string& expected_algorithm,
520 bool expected_extractable,
521 blink::WebCryptoKeyUsageMask expected_usage_mask,
522 std::vector<uint8_t>* raw_key_data) {
523 scoped_ptr<base::DictionaryValue> dict;
524 Status status = ReadSecretKeyNoExpectedAlg(
525 key_data, expected_extractable, expected_usage_mask, raw_key_data, &dict);
526 if (status.IsError())
527 return status;
528 return VerifyAlg(dict.get(), expected_algorithm);
531 std::string MakeJwkAesAlgorithmName(const std::string& suffix,
532 unsigned int keylen_bytes) {
533 if (keylen_bytes == 16)
534 return std::string("A128") + suffix;
535 if (keylen_bytes == 24)
536 return std::string("A192") + suffix;
537 if (keylen_bytes == 32)
538 return std::string("A256") + suffix;
539 return std::string();
542 Status ReadAesSecretKeyJwk(const CryptoData& key_data,
543 const std::string& algorithm_name_suffix,
544 bool expected_extractable,
545 blink::WebCryptoKeyUsageMask expected_usage_mask,
546 std::vector<uint8_t>* raw_key_data) {
547 scoped_ptr<base::DictionaryValue> dict;
548 Status status = ReadSecretKeyNoExpectedAlg(
549 key_data, expected_extractable, expected_usage_mask, raw_key_data, &dict);
550 if (status.IsError())
551 return status;
553 bool has_jwk_alg;
554 std::string jwk_alg;
555 status = GetOptionalJwkString(dict.get(), "alg", &jwk_alg, &has_jwk_alg);
556 if (status.IsError())
557 return status;
559 if (has_jwk_alg) {
560 std::string expected_algorithm_name =
561 MakeJwkAesAlgorithmName(algorithm_name_suffix, raw_key_data->size());
563 if (jwk_alg != expected_algorithm_name) {
564 // Give a different error message if the key length was wrong.
565 if (jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 16) ||
566 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 24) ||
567 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 32)) {
568 return Status::ErrorJwkIncorrectKeyLength();
570 return Status::ErrorJwkAlgorithmInconsistent();
574 return Status::Success();
577 // Writes an RSA public key to a JWK dictionary
578 void WriteRsaPublicKeyJwk(const CryptoData& n,
579 const CryptoData& e,
580 const std::string& algorithm,
581 bool extractable,
582 blink::WebCryptoKeyUsageMask usage_mask,
583 std::vector<uint8_t>* jwk_key_data) {
584 JwkWriter writer(algorithm, extractable, usage_mask, "RSA");
585 writer.SetBase64Encoded("n", n);
586 writer.SetBase64Encoded("e", e);
587 writer.ToBytes(jwk_key_data);
590 // Writes an RSA private key to a JWK dictionary
591 void WriteRsaPrivateKeyJwk(const CryptoData& n,
592 const CryptoData& e,
593 const CryptoData& d,
594 const CryptoData& p,
595 const CryptoData& q,
596 const CryptoData& dp,
597 const CryptoData& dq,
598 const CryptoData& qi,
599 const std::string& algorithm,
600 bool extractable,
601 blink::WebCryptoKeyUsageMask usage_mask,
602 std::vector<uint8_t>* jwk_key_data) {
603 JwkWriter writer(algorithm, extractable, usage_mask, "RSA");
605 writer.SetBase64Encoded("n", n);
606 writer.SetBase64Encoded("e", e);
607 writer.SetBase64Encoded("d", d);
608 // Although these are "optional" in the JWA, WebCrypto spec requires them to
609 // be emitted.
610 writer.SetBase64Encoded("p", p);
611 writer.SetBase64Encoded("q", q);
612 writer.SetBase64Encoded("dp", dp);
613 writer.SetBase64Encoded("dq", dq);
614 writer.SetBase64Encoded("qi", qi);
615 writer.ToBytes(jwk_key_data);
618 JwkRsaInfo::JwkRsaInfo() : is_private_key(false) {
621 JwkRsaInfo::~JwkRsaInfo() {
624 Status ReadRsaKeyJwk(const CryptoData& key_data,
625 const std::string& expected_algorithm,
626 bool expected_extractable,
627 blink::WebCryptoKeyUsageMask expected_usage_mask,
628 JwkRsaInfo* result) {
629 if (!key_data.byte_length())
630 return Status::ErrorImportEmptyKeyData();
632 scoped_ptr<base::DictionaryValue> dict;
633 std::string kty;
634 Status status = ParseJwkCommon(
635 key_data, expected_extractable, expected_usage_mask, &kty, &dict);
636 if (status.IsError())
637 return status;
639 status = VerifyAlg(dict.get(), expected_algorithm);
640 if (status.IsError())
641 return status;
643 if (kty != "RSA")
644 return Status::ErrorJwkUnexpectedKty("RSA");
646 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
647 // in the JWK, while an RSA private key must have those, plus at least a "d"
648 // (private exponent) entry.
649 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
650 // section 6.3.
651 status = GetJwkBigInteger(dict.get(), "n", &result->n);
652 if (status.IsError())
653 return status;
654 status = GetJwkBigInteger(dict.get(), "e", &result->e);
655 if (status.IsError())
656 return status;
658 result->is_private_key = dict->HasKey("d");
659 if (!result->is_private_key)
660 return Status::Success();
662 status = GetJwkBigInteger(dict.get(), "d", &result->d);
663 if (status.IsError())
664 return status;
666 // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA
667 // spec. However they are required by Chromium's WebCrypto implementation.
669 status = GetJwkBigInteger(dict.get(), "p", &result->p);
670 if (status.IsError())
671 return status;
673 status = GetJwkBigInteger(dict.get(), "q", &result->q);
674 if (status.IsError())
675 return status;
677 status = GetJwkBigInteger(dict.get(), "dp", &result->dp);
678 if (status.IsError())
679 return status;
681 status = GetJwkBigInteger(dict.get(), "dq", &result->dq);
682 if (status.IsError())
683 return status;
685 status = GetJwkBigInteger(dict.get(), "qi", &result->qi);
686 if (status.IsError())
687 return status;
689 return Status::Success();
692 const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) {
693 switch (hash) {
694 case blink::WebCryptoAlgorithmIdSha1:
695 return "HS1";
696 case blink::WebCryptoAlgorithmIdSha256:
697 return "HS256";
698 case blink::WebCryptoAlgorithmIdSha384:
699 return "HS384";
700 case blink::WebCryptoAlgorithmIdSha512:
701 return "HS512";
702 default:
703 return NULL;
707 // TODO(eroman): This accepts invalid inputs. http://crbug.com/378034
708 bool Base64DecodeUrlSafe(const std::string& input, std::string* output) {
709 std::string base64_encoded_text(input);
710 std::replace(
711 base64_encoded_text.begin(), base64_encoded_text.end(), '-', '+');
712 std::replace(
713 base64_encoded_text.begin(), base64_encoded_text.end(), '_', '/');
714 base64_encoded_text.append((4 - base64_encoded_text.size() % 4) % 4, '=');
715 return base::Base64Decode(base64_encoded_text, output);
718 std::string Base64EncodeUrlSafe(const base::StringPiece& input) {
719 std::string output;
720 base::Base64Encode(input, &output);
721 std::replace(output.begin(), output.end(), '+', '-');
722 std::replace(output.begin(), output.end(), '/', '_');
723 output.erase(std::remove(output.begin(), output.end(), '='), output.end());
724 return output;
727 std::string Base64EncodeUrlSafe(const std::vector<uint8_t>& input) {
728 const base::StringPiece string_piece(
729 reinterpret_cast<const char*>(vector_as_array(&input)), input.size());
730 return Base64EncodeUrlSafe(string_piece);
733 } // namespace webcrypto
735 } // namespace content