OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "content/child/webcrypto/jwk.h" | |
6 | |
7 #include <set> | |
8 | |
9 #include "base/base64.h" | |
10 #include "base/json/json_reader.h" | |
11 #include "base/json/json_writer.h" | |
12 #include "base/stl_util.h" | |
13 #include "base/strings/string_piece.h" | |
14 #include "base/strings/stringprintf.h" | |
15 #include "content/child/webcrypto/crypto_data.h" | |
16 #include "content/child/webcrypto/status.h" | |
17 #include "content/child/webcrypto/webcrypto_util.h" | |
18 | |
19 // TODO(eroman): The algorithm-specific logic in this file for AES and RSA | |
20 // should be moved into the corresponding AlgorithmImplementation file. It | |
21 // exists in this file to avoid duplication between OpenSSL and NSS | |
22 // implementations. | |
23 | |
24 // JSON Web Key Format (JWK) is defined by: | |
25 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key | |
26 // | |
27 // A JWK is a simple JSON dictionary with the following members: | |
28 // - "kty" (Key Type) Parameter, REQUIRED | |
29 // - <kty-specific parameters, see below>, REQUIRED | |
30 // - "use" (Key Use) OPTIONAL | |
31 // - "key_ops" (Key Operations) OPTIONAL | |
32 // - "alg" (Algorithm) OPTIONAL | |
33 // - "ext" (Key Exportability), OPTIONAL | |
34 // (all other entries are ignored) | |
35 // | |
36 // The <kty-specific parameters> are defined by the JWA spec: | |
37 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms | |
38 | |
39 namespace content { | |
40 | |
41 namespace webcrypto { | |
42 | |
43 namespace { | |
44 | |
45 // Web Crypto equivalent usage mask for JWK 'use' = 'enc'. | |
46 const blink::WebCryptoKeyUsageMask kJwkEncUsage = | |
47 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt | | |
48 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey; | |
49 // Web Crypto equivalent usage mask for JWK 'use' = 'sig'. | |
50 const blink::WebCryptoKeyUsageMask kJwkSigUsage = | |
51 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; | |
52 | |
53 // Checks that the "ext" member of the JWK is consistent with | |
54 // "expected_extractable". | |
55 Status VerifyExt(const JwkReader& jwk, bool expected_extractable) { | |
56 // JWK "ext" (optional) --> extractable parameter | |
57 bool jwk_ext_value = false; | |
58 bool has_jwk_ext; | |
59 Status status = jwk.GetOptionalBool("ext", &jwk_ext_value, &has_jwk_ext); | |
60 if (status.IsError()) | |
61 return status; | |
62 if (has_jwk_ext && expected_extractable && !jwk_ext_value) | |
63 return Status::ErrorJwkExtInconsistent(); | |
64 return Status::Success(); | |
65 } | |
66 | |
67 struct JwkToWebCryptoUsageMapping { | |
68 const char* const jwk_key_op; | |
69 const blink::WebCryptoKeyUsage webcrypto_usage; | |
70 }; | |
71 | |
72 // Keep this ordered the same as WebCrypto's "recognized key usage | |
73 // values". While this is not required for spec compliance, | |
74 // it makes the ordering of key_ops match that of WebCrypto's Key.usages. | |
75 const JwkToWebCryptoUsageMapping kJwkWebCryptoUsageMap[] = { | |
76 {"encrypt", blink::WebCryptoKeyUsageEncrypt}, | |
77 {"decrypt", blink::WebCryptoKeyUsageDecrypt}, | |
78 {"sign", blink::WebCryptoKeyUsageSign}, | |
79 {"verify", blink::WebCryptoKeyUsageVerify}, | |
80 {"deriveKey", blink::WebCryptoKeyUsageDeriveKey}, | |
81 {"deriveBits", blink::WebCryptoKeyUsageDeriveBits}, | |
82 {"wrapKey", blink::WebCryptoKeyUsageWrapKey}, | |
83 {"unwrapKey", blink::WebCryptoKeyUsageUnwrapKey}}; | |
84 | |
85 bool JwkKeyOpToWebCryptoUsage(const std::string& key_op, | |
86 blink::WebCryptoKeyUsage* usage) { | |
87 for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) { | |
88 if (kJwkWebCryptoUsageMap[i].jwk_key_op == key_op) { | |
89 *usage = kJwkWebCryptoUsageMap[i].webcrypto_usage; | |
90 return true; | |
91 } | |
92 } | |
93 return false; | |
94 } | |
95 | |
96 // Creates a JWK key_ops list from a Web Crypto usage mask. | |
97 scoped_ptr<base::ListValue> CreateJwkKeyOpsFromWebCryptoUsages( | |
98 blink::WebCryptoKeyUsageMask usages) { | |
99 scoped_ptr<base::ListValue> jwk_key_ops(new base::ListValue()); | |
100 for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) { | |
101 if (usages & kJwkWebCryptoUsageMap[i].webcrypto_usage) | |
102 jwk_key_ops->AppendString(kJwkWebCryptoUsageMap[i].jwk_key_op); | |
103 } | |
104 return jwk_key_ops.Pass(); | |
105 } | |
106 | |
107 // Composes a Web Crypto usage mask from an array of JWK key_ops values. | |
108 Status GetWebCryptoUsagesFromJwkKeyOps(const base::ListValue* key_ops, | |
109 blink::WebCryptoKeyUsageMask* usages) { | |
110 // This set keeps track of all unrecognized key_ops values. | |
111 std::set<std::string> unrecognized_usages; | |
112 | |
113 *usages = 0; | |
114 for (size_t i = 0; i < key_ops->GetSize(); ++i) { | |
115 std::string key_op; | |
116 if (!key_ops->GetString(i, &key_op)) { | |
117 return Status::ErrorJwkMemberWrongType( | |
118 base::StringPrintf("key_ops[%d]", static_cast<int>(i)), "string"); | |
119 } | |
120 | |
121 blink::WebCryptoKeyUsage usage; | |
122 if (JwkKeyOpToWebCryptoUsage(key_op, &usage)) { | |
123 // Ensure there are no duplicate usages. | |
124 if (*usages & usage) | |
125 return Status::ErrorJwkDuplicateKeyOps(); | |
126 *usages |= usage; | |
127 } | |
128 | |
129 // Reaching here means the usage was unrecognized. Such usages are skipped | |
130 // over, however they are kept track of in a set to ensure there were no | |
131 // duplicates. | |
132 if (!unrecognized_usages.insert(key_op).second) | |
133 return Status::ErrorJwkDuplicateKeyOps(); | |
134 } | |
135 return Status::Success(); | |
136 } | |
137 | |
138 // Checks that the usages ("use" and "key_ops") of the JWK is consistent with | |
139 // "expected_usages". | |
140 Status VerifyUsages(const JwkReader& jwk, | |
141 blink::WebCryptoKeyUsageMask expected_usages) { | |
142 // JWK "key_ops" (optional) --> usages parameter | |
143 base::ListValue* jwk_key_ops_value = NULL; | |
144 bool has_jwk_key_ops; | |
145 Status status = | |
146 jwk.GetOptionalList("key_ops", &jwk_key_ops_value, &has_jwk_key_ops); | |
147 if (status.IsError()) | |
148 return status; | |
149 blink::WebCryptoKeyUsageMask jwk_key_ops_mask = 0; | |
150 if (has_jwk_key_ops) { | |
151 status = | |
152 GetWebCryptoUsagesFromJwkKeyOps(jwk_key_ops_value, &jwk_key_ops_mask); | |
153 if (status.IsError()) | |
154 return status; | |
155 // The input usages must be a subset of jwk_key_ops_mask. | |
156 if (!ContainsKeyUsages(jwk_key_ops_mask, expected_usages)) | |
157 return Status::ErrorJwkKeyopsInconsistent(); | |
158 } | |
159 | |
160 // JWK "use" (optional) --> usages parameter | |
161 std::string jwk_use_value; | |
162 bool has_jwk_use; | |
163 status = jwk.GetOptionalString("use", &jwk_use_value, &has_jwk_use); | |
164 if (status.IsError()) | |
165 return status; | |
166 blink::WebCryptoKeyUsageMask jwk_use_mask = 0; | |
167 if (has_jwk_use) { | |
168 if (jwk_use_value == "enc") | |
169 jwk_use_mask = kJwkEncUsage; | |
170 else if (jwk_use_value == "sig") | |
171 jwk_use_mask = kJwkSigUsage; | |
172 else | |
173 return Status::ErrorJwkUnrecognizedUse(); | |
174 // The input usages must be a subset of jwk_use_mask. | |
175 if (!ContainsKeyUsages(jwk_use_mask, expected_usages)) | |
176 return Status::ErrorJwkUseInconsistent(); | |
177 } | |
178 | |
179 // If both 'key_ops' and 'use' are present, ensure they are consistent. | |
180 if (has_jwk_key_ops && has_jwk_use && | |
181 !ContainsKeyUsages(jwk_use_mask, jwk_key_ops_mask)) | |
182 return Status::ErrorJwkUseAndKeyopsInconsistent(); | |
183 | |
184 return Status::Success(); | |
185 } | |
186 | |
187 } // namespace | |
188 | |
189 JwkReader::JwkReader() { | |
190 } | |
191 | |
192 JwkReader::~JwkReader() { | |
193 } | |
194 | |
195 Status JwkReader::Init(const CryptoData& bytes, | |
196 bool expected_extractable, | |
197 blink::WebCryptoKeyUsageMask expected_usages, | |
198 const std::string& expected_kty, | |
199 const std::string& expected_alg) { | |
200 // Parse the incoming JWK JSON. | |
201 base::StringPiece json_string(reinterpret_cast<const char*>(bytes.bytes()), | |
202 bytes.byte_length()); | |
203 | |
204 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string)); | |
205 base::DictionaryValue* dict_value = NULL; | |
206 | |
207 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value) | |
208 return Status::ErrorJwkNotDictionary(); | |
209 | |
210 // Release |value|, as ownership will be transferred to |dict| via | |
211 // |dict_value|, which points to the same object as |value|. | |
212 ignore_result(value.release()); | |
213 dict_.reset(dict_value); | |
214 | |
215 // JWK "kty". Exit early if this required JWK parameter is missing. | |
216 std::string kty; | |
217 Status status = GetString("kty", &kty); | |
218 if (status.IsError()) | |
219 return status; | |
220 | |
221 if (kty != expected_kty) | |
222 return Status::ErrorJwkUnexpectedKty(expected_kty); | |
223 | |
224 status = VerifyExt(*this, expected_extractable); | |
225 if (status.IsError()) | |
226 return status; | |
227 | |
228 status = VerifyUsages(*this, expected_usages); | |
229 if (status.IsError()) | |
230 return status; | |
231 | |
232 // Verify the algorithm if an expectation was provided. | |
233 if (!expected_alg.empty()) { | |
234 status = VerifyAlg(expected_alg); | |
235 if (status.IsError()) | |
236 return status; | |
237 } | |
238 | |
239 return Status::Success(); | |
240 } | |
241 | |
242 bool JwkReader::HasMember(const std::string& member_name) const { | |
243 return dict_->HasKey(member_name); | |
244 } | |
245 | |
246 Status JwkReader::GetString(const std::string& member_name, | |
247 std::string* result) const { | |
248 base::Value* value = NULL; | |
249 if (!dict_->Get(member_name, &value)) | |
250 return Status::ErrorJwkMemberMissing(member_name); | |
251 if (!value->GetAsString(result)) | |
252 return Status::ErrorJwkMemberWrongType(member_name, "string"); | |
253 return Status::Success(); | |
254 } | |
255 | |
256 Status JwkReader::GetOptionalString(const std::string& member_name, | |
257 std::string* result, | |
258 bool* member_exists) const { | |
259 *member_exists = false; | |
260 base::Value* value = NULL; | |
261 if (!dict_->Get(member_name, &value)) | |
262 return Status::Success(); | |
263 | |
264 if (!value->GetAsString(result)) | |
265 return Status::ErrorJwkMemberWrongType(member_name, "string"); | |
266 | |
267 *member_exists = true; | |
268 return Status::Success(); | |
269 } | |
270 | |
271 Status JwkReader::GetOptionalList(const std::string& member_name, | |
272 base::ListValue** result, | |
273 bool* member_exists) const { | |
274 *member_exists = false; | |
275 base::Value* value = NULL; | |
276 if (!dict_->Get(member_name, &value)) | |
277 return Status::Success(); | |
278 | |
279 if (!value->GetAsList(result)) | |
280 return Status::ErrorJwkMemberWrongType(member_name, "list"); | |
281 | |
282 *member_exists = true; | |
283 return Status::Success(); | |
284 } | |
285 | |
286 Status JwkReader::GetBytes(const std::string& member_name, | |
287 std::string* result) const { | |
288 std::string base64_string; | |
289 Status status = GetString(member_name, &base64_string); | |
290 if (status.IsError()) | |
291 return status; | |
292 | |
293 if (!Base64DecodeUrlSafe(base64_string, result)) | |
294 return Status::ErrorJwkBase64Decode(member_name); | |
295 | |
296 return Status::Success(); | |
297 } | |
298 | |
299 Status JwkReader::GetBigInteger(const std::string& member_name, | |
300 std::string* result) const { | |
301 Status status = GetBytes(member_name, result); | |
302 if (status.IsError()) | |
303 return status; | |
304 | |
305 if (result->empty()) | |
306 return Status::ErrorJwkEmptyBigInteger(member_name); | |
307 | |
308 // The JWA spec says that "The octet sequence MUST utilize the minimum number | |
309 // of octets to represent the value." This means there shouldn't be any | |
310 // leading zeros. | |
311 if (result->size() > 1 && (*result)[0] == 0) | |
312 return Status::ErrorJwkBigIntegerHasLeadingZero(member_name); | |
313 | |
314 return Status::Success(); | |
315 } | |
316 | |
317 Status JwkReader::GetOptionalBool(const std::string& member_name, | |
318 bool* result, | |
319 bool* member_exists) const { | |
320 *member_exists = false; | |
321 base::Value* value = NULL; | |
322 if (!dict_->Get(member_name, &value)) | |
323 return Status::Success(); | |
324 | |
325 if (!value->GetAsBoolean(result)) | |
326 return Status::ErrorJwkMemberWrongType(member_name, "boolean"); | |
327 | |
328 *member_exists = true; | |
329 return Status::Success(); | |
330 } | |
331 | |
332 Status JwkReader::GetAlg(std::string* alg, bool* has_alg) const { | |
333 return GetOptionalString("alg", alg, has_alg); | |
334 } | |
335 | |
336 Status JwkReader::VerifyAlg(const std::string& expected_alg) const { | |
337 bool has_jwk_alg; | |
338 std::string jwk_alg_value; | |
339 Status status = GetAlg(&jwk_alg_value, &has_jwk_alg); | |
340 if (status.IsError()) | |
341 return status; | |
342 | |
343 if (has_jwk_alg && jwk_alg_value != expected_alg) | |
344 return Status::ErrorJwkAlgorithmInconsistent(); | |
345 | |
346 return Status::Success(); | |
347 } | |
348 | |
349 JwkWriter::JwkWriter(const std::string& algorithm, | |
350 bool extractable, | |
351 blink::WebCryptoKeyUsageMask usages, | |
352 const std::string& kty) { | |
353 if (!algorithm.empty()) | |
354 dict_.SetString("alg", algorithm); | |
355 dict_.Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(usages).release()); | |
356 dict_.SetBoolean("ext", extractable); | |
357 dict_.SetString("kty", kty); | |
358 } | |
359 | |
360 void JwkWriter::SetString(const std::string& member_name, | |
361 const std::string& value) { | |
362 dict_.SetString(member_name, value); | |
363 } | |
364 | |
365 void JwkWriter::SetBytes(const std::string& member_name, | |
366 const CryptoData& value) { | |
367 dict_.SetString(member_name, Base64EncodeUrlSafe(base::StringPiece( | |
368 reinterpret_cast<const char*>(value.bytes()), | |
369 value.byte_length()))); | |
370 } | |
371 | |
372 void JwkWriter::ToJson(std::vector<uint8_t>* utf8_bytes) const { | |
373 std::string json; | |
374 base::JSONWriter::Write(&dict_, &json); | |
375 utf8_bytes->assign(json.begin(), json.end()); | |
376 } | |
377 | |
378 Status ReadSecretKeyNoExpectedAlg(const CryptoData& key_data, | |
379 bool expected_extractable, | |
380 blink::WebCryptoKeyUsageMask expected_usages, | |
381 std::vector<uint8_t>* raw_key_data, | |
382 JwkReader* jwk) { | |
383 Status status = jwk->Init(key_data, expected_extractable, expected_usages, | |
384 "oct", std::string()); | |
385 if (status.IsError()) | |
386 return status; | |
387 | |
388 std::string jwk_k_value; | |
389 status = jwk->GetBytes("k", &jwk_k_value); | |
390 if (status.IsError()) | |
391 return status; | |
392 raw_key_data->assign(jwk_k_value.begin(), jwk_k_value.end()); | |
393 | |
394 return Status::Success(); | |
395 } | |
396 | |
397 void WriteSecretKeyJwk(const CryptoData& raw_key_data, | |
398 const std::string& algorithm, | |
399 bool extractable, | |
400 blink::WebCryptoKeyUsageMask usages, | |
401 std::vector<uint8_t>* jwk_key_data) { | |
402 JwkWriter writer(algorithm, extractable, usages, "oct"); | |
403 writer.SetBytes("k", raw_key_data); | |
404 writer.ToJson(jwk_key_data); | |
405 } | |
406 | |
407 Status ReadSecretKeyJwk(const CryptoData& key_data, | |
408 const std::string& expected_alg, | |
409 bool expected_extractable, | |
410 blink::WebCryptoKeyUsageMask expected_usages, | |
411 std::vector<uint8_t>* raw_key_data) { | |
412 JwkReader jwk; | |
413 Status status = ReadSecretKeyNoExpectedAlg( | |
414 key_data, expected_extractable, expected_usages, raw_key_data, &jwk); | |
415 if (status.IsError()) | |
416 return status; | |
417 return jwk.VerifyAlg(expected_alg); | |
418 } | |
419 | |
420 std::string MakeJwkAesAlgorithmName(const std::string& suffix, | |
421 unsigned int keylen_bytes) { | |
422 if (keylen_bytes == 16) | |
423 return std::string("A128") + suffix; | |
424 if (keylen_bytes == 24) | |
425 return std::string("A192") + suffix; | |
426 if (keylen_bytes == 32) | |
427 return std::string("A256") + suffix; | |
428 return std::string(); | |
429 } | |
430 | |
431 Status ReadAesSecretKeyJwk(const CryptoData& key_data, | |
432 const std::string& algorithm_name_suffix, | |
433 bool expected_extractable, | |
434 blink::WebCryptoKeyUsageMask expected_usages, | |
435 std::vector<uint8_t>* raw_key_data) { | |
436 JwkReader jwk; | |
437 Status status = ReadSecretKeyNoExpectedAlg( | |
438 key_data, expected_extractable, expected_usages, raw_key_data, &jwk); | |
439 if (status.IsError()) | |
440 return status; | |
441 | |
442 bool has_jwk_alg; | |
443 std::string jwk_alg; | |
444 status = jwk.GetAlg(&jwk_alg, &has_jwk_alg); | |
445 if (status.IsError()) | |
446 return status; | |
447 | |
448 if (has_jwk_alg) { | |
449 std::string expected_algorithm_name = | |
450 MakeJwkAesAlgorithmName(algorithm_name_suffix, raw_key_data->size()); | |
451 | |
452 if (jwk_alg != expected_algorithm_name) { | |
453 // Give a different error message if the key length was wrong. | |
454 if (jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 16) || | |
455 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 24) || | |
456 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 32)) { | |
457 return Status::ErrorJwkIncorrectKeyLength(); | |
458 } | |
459 return Status::ErrorJwkAlgorithmInconsistent(); | |
460 } | |
461 } | |
462 | |
463 return Status::Success(); | |
464 } | |
465 | |
466 // Writes an RSA public key to a JWK dictionary | |
467 void WriteRsaPublicKeyJwk(const CryptoData& n, | |
468 const CryptoData& e, | |
469 const std::string& algorithm, | |
470 bool extractable, | |
471 blink::WebCryptoKeyUsageMask usages, | |
472 std::vector<uint8_t>* jwk_key_data) { | |
473 JwkWriter writer(algorithm, extractable, usages, "RSA"); | |
474 writer.SetBytes("n", n); | |
475 writer.SetBytes("e", e); | |
476 writer.ToJson(jwk_key_data); | |
477 } | |
478 | |
479 // Writes an RSA private key to a JWK dictionary | |
480 void WriteRsaPrivateKeyJwk(const CryptoData& n, | |
481 const CryptoData& e, | |
482 const CryptoData& d, | |
483 const CryptoData& p, | |
484 const CryptoData& q, | |
485 const CryptoData& dp, | |
486 const CryptoData& dq, | |
487 const CryptoData& qi, | |
488 const std::string& algorithm, | |
489 bool extractable, | |
490 blink::WebCryptoKeyUsageMask usages, | |
491 std::vector<uint8_t>* jwk_key_data) { | |
492 JwkWriter writer(algorithm, extractable, usages, "RSA"); | |
493 | |
494 writer.SetBytes("n", n); | |
495 writer.SetBytes("e", e); | |
496 writer.SetBytes("d", d); | |
497 // Although these are "optional" in the JWA, WebCrypto spec requires them to | |
498 // be emitted. | |
499 writer.SetBytes("p", p); | |
500 writer.SetBytes("q", q); | |
501 writer.SetBytes("dp", dp); | |
502 writer.SetBytes("dq", dq); | |
503 writer.SetBytes("qi", qi); | |
504 writer.ToJson(jwk_key_data); | |
505 } | |
506 | |
507 JwkRsaInfo::JwkRsaInfo() : is_private_key(false) { | |
508 } | |
509 | |
510 JwkRsaInfo::~JwkRsaInfo() { | |
511 } | |
512 | |
513 Status ReadRsaKeyJwk(const CryptoData& key_data, | |
514 const std::string& expected_alg, | |
515 bool expected_extractable, | |
516 blink::WebCryptoKeyUsageMask expected_usages, | |
517 JwkRsaInfo* result) { | |
518 JwkReader jwk; | |
519 Status status = jwk.Init(key_data, expected_extractable, expected_usages, | |
520 "RSA", expected_alg); | |
521 if (status.IsError()) | |
522 return status; | |
523 | |
524 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry | |
525 // in the JWK, while an RSA private key must have those, plus at least a "d" | |
526 // (private exponent) entry. | |
527 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18, | |
528 // section 6.3. | |
529 status = jwk.GetBigInteger("n", &result->n); | |
530 if (status.IsError()) | |
531 return status; | |
532 status = jwk.GetBigInteger("e", &result->e); | |
533 if (status.IsError()) | |
534 return status; | |
535 | |
536 result->is_private_key = jwk.HasMember("d"); | |
537 if (!result->is_private_key) | |
538 return Status::Success(); | |
539 | |
540 status = jwk.GetBigInteger("d", &result->d); | |
541 if (status.IsError()) | |
542 return status; | |
543 | |
544 // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA | |
545 // spec. However they are required by Chromium's WebCrypto implementation. | |
546 | |
547 status = jwk.GetBigInteger("p", &result->p); | |
548 if (status.IsError()) | |
549 return status; | |
550 | |
551 status = jwk.GetBigInteger("q", &result->q); | |
552 if (status.IsError()) | |
553 return status; | |
554 | |
555 status = jwk.GetBigInteger("dp", &result->dp); | |
556 if (status.IsError()) | |
557 return status; | |
558 | |
559 status = jwk.GetBigInteger("dq", &result->dq); | |
560 if (status.IsError()) | |
561 return status; | |
562 | |
563 status = jwk.GetBigInteger("qi", &result->qi); | |
564 if (status.IsError()) | |
565 return status; | |
566 | |
567 return Status::Success(); | |
568 } | |
569 | |
570 const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) { | |
571 switch (hash) { | |
572 case blink::WebCryptoAlgorithmIdSha1: | |
573 return "HS1"; | |
574 case blink::WebCryptoAlgorithmIdSha256: | |
575 return "HS256"; | |
576 case blink::WebCryptoAlgorithmIdSha384: | |
577 return "HS384"; | |
578 case blink::WebCryptoAlgorithmIdSha512: | |
579 return "HS512"; | |
580 default: | |
581 return NULL; | |
582 } | |
583 } | |
584 | |
585 bool Base64DecodeUrlSafe(const std::string& input, std::string* output) { | |
586 // The JSON web signature spec specifically says that padding is omitted. | |
587 if (input.find_first_of("+/=") != std::string::npos) | |
588 return false; | |
589 | |
590 std::string base64_encoded_text(input); | |
591 std::replace(base64_encoded_text.begin(), base64_encoded_text.end(), '-', | |
592 '+'); | |
593 std::replace(base64_encoded_text.begin(), base64_encoded_text.end(), '_', | |
594 '/'); | |
595 base64_encoded_text.append((4 - base64_encoded_text.size() % 4) % 4, '='); | |
596 return base::Base64Decode(base64_encoded_text, output); | |
597 } | |
598 | |
599 std::string Base64EncodeUrlSafe(const base::StringPiece& input) { | |
600 std::string output; | |
601 base::Base64Encode(input, &output); | |
602 std::replace(output.begin(), output.end(), '+', '-'); | |
603 std::replace(output.begin(), output.end(), '/', '_'); | |
604 output.erase(std::remove(output.begin(), output.end(), '='), output.end()); | |
605 return output; | |
606 } | |
607 | |
608 std::string Base64EncodeUrlSafe(const std::vector<uint8_t>& input) { | |
609 const base::StringPiece string_piece( | |
610 reinterpret_cast<const char*>(vector_as_array(&input)), input.size()); | |
611 return Base64EncodeUrlSafe(string_piece); | |
612 } | |
613 | |
614 Status GetWebCryptoUsagesFromJwkKeyOpsForTest( | |
615 const base::ListValue* key_ops, | |
616 blink::WebCryptoKeyUsageMask* usages) { | |
617 return GetWebCryptoUsagesFromJwkKeyOps(key_ops, usages); | |
618 } | |
619 | |
620 } // namespace webcrypto | |
621 | |
622 } // namespace content | |
OLD | NEW |