OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "jwk.h" | 5 #include "content/child/webcrypto/jwk.h" |
6 | |
7 #include <algorithm> | |
8 #include <functional> | |
9 #include <map> | |
10 | 6 |
11 #include "base/base64.h" | 7 #include "base/base64.h" |
12 #include "base/json/json_reader.h" | 8 #include "base/json/json_reader.h" |
13 #include "base/json/json_writer.h" | 9 #include "base/json/json_writer.h" |
14 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
15 #include "base/strings/string_piece.h" | 11 #include "base/strings/string_piece.h" |
16 #include "content/child/webcrypto/crypto_data.h" | 12 #include "content/child/webcrypto/crypto_data.h" |
17 #include "content/child/webcrypto/status.h" | 13 #include "content/child/webcrypto/status.h" |
18 #include "content/child/webcrypto/webcrypto_util.h" | 14 #include "content/child/webcrypto/webcrypto_util.h" |
19 | 15 |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
213 | 209 |
214 // Web Crypto equivalent usage mask for JWK 'use' = 'enc'. | 210 // Web Crypto equivalent usage mask for JWK 'use' = 'enc'. |
215 const blink::WebCryptoKeyUsageMask kJwkEncUsage = | 211 const blink::WebCryptoKeyUsageMask kJwkEncUsage = |
216 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt | | 212 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt | |
217 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey | | 213 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey | |
218 blink::WebCryptoKeyUsageDeriveKey | blink::WebCryptoKeyUsageDeriveBits; | 214 blink::WebCryptoKeyUsageDeriveKey | blink::WebCryptoKeyUsageDeriveBits; |
219 // Web Crypto equivalent usage mask for JWK 'use' = 'sig'. | 215 // Web Crypto equivalent usage mask for JWK 'use' = 'sig'. |
220 const blink::WebCryptoKeyUsageMask kJwkSigUsage = | 216 const blink::WebCryptoKeyUsageMask kJwkSigUsage = |
221 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; | 217 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; |
222 | 218 |
223 class JwkWriter { | 219 // Checks that the "ext" property of the JWK is consistent with |
eroman
2014/10/29 02:35:11
This class declaration was moved into the header
| |
224 public: | 220 // "expected_extractable". |
225 JwkWriter(const std::string& algorithm, | 221 Status VerifyExt(const JwkReader& jwk, bool expected_extractable) { |
226 bool extractable, | |
227 blink::WebCryptoKeyUsageMask usages, | |
228 const std::string& kty) { | |
229 dict_.SetString("alg", algorithm); | |
230 dict_.Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(usages)); | |
231 dict_.SetBoolean("ext", extractable); | |
232 dict_.SetString("kty", kty); | |
233 } | |
234 | |
235 void Set(const std::string& key, const std::string& value) { | |
236 dict_.SetString(key, value); | |
237 } | |
238 | |
239 void SetBase64Encoded(const std::string& key, const CryptoData& value) { | |
eroman
2014/10/29 02:35:11
Renamed this to SetBytes()
| |
240 dict_.SetString(key, | |
241 Base64EncodeUrlSafe(base::StringPiece( | |
242 reinterpret_cast<const char*>(value.bytes()), | |
243 value.byte_length()))); | |
244 } | |
245 | |
246 void ToBytes(std::vector<uint8_t>* utf8_bytes) { | |
eroman
2014/10/29 02:35:11
Renamed this to ToJson()
| |
247 std::string json; | |
248 base::JSONWriter::Write(&dict_, &json); | |
249 utf8_bytes->assign(json.begin(), json.end()); | |
250 } | |
251 | |
252 private: | |
253 base::DictionaryValue dict_; | |
254 }; | |
255 | |
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, | |
eroman
2014/10/29 02:35:11
The following functions were moved further down in
| |
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(); | |
268 } | |
269 | |
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(); | |
282 | |
283 if (!value->GetAsString(result)) | |
284 return Status::ErrorJwkPropertyWrongType(path, "string"); | |
285 | |
286 *property_exists = true; | |
287 return Status::Success(); | |
288 } | |
289 | |
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(); | |
302 | |
303 if (!value->GetAsList(result)) | |
304 return Status::ErrorJwkPropertyWrongType(path, "list"); | |
305 | |
306 *property_exists = true; | |
307 return Status::Success(); | |
308 } | |
309 | |
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; | |
320 | |
321 if (!Base64DecodeUrlSafe(base64_string, result)) | |
322 return Status::ErrorJwkBase64Decode(path); | |
323 | |
324 return Status::Success(); | |
325 } | |
326 | |
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; | |
335 | |
336 if (result->empty()) | |
337 return Status::ErrorJwkEmptyBigInteger(path); | |
338 | |
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); | |
344 | |
345 return Status::Success(); | |
346 } | |
347 | |
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(); | |
360 | |
361 if (!value->GetAsBoolean(result)) | |
362 return Status::ErrorJwkPropertyWrongType(path, "boolean"); | |
363 | |
364 *property_exists = true; | |
365 return Status::Success(); | |
366 } | |
367 | |
368 Status VerifyExt(base::DictionaryValue* dict, bool expected_extractable) { | |
369 // JWK "ext" (optional) --> extractable parameter | 222 // JWK "ext" (optional) --> extractable parameter |
370 bool jwk_ext_value = false; | 223 bool jwk_ext_value = false; |
371 bool has_jwk_ext; | 224 bool has_jwk_ext; |
372 Status status = GetOptionalJwkBool(dict, "ext", &jwk_ext_value, &has_jwk_ext); | 225 Status status = jwk.GetOptionalBool("ext", &jwk_ext_value, &has_jwk_ext); |
373 if (status.IsError()) | 226 if (status.IsError()) |
374 return status; | 227 return status; |
375 if (has_jwk_ext && expected_extractable && !jwk_ext_value) | 228 if (has_jwk_ext && expected_extractable && !jwk_ext_value) |
376 return Status::ErrorJwkExtInconsistent(); | 229 return Status::ErrorJwkExtInconsistent(); |
377 return Status::Success(); | 230 return Status::Success(); |
378 } | 231 } |
379 | 232 |
380 Status VerifyUsages(base::DictionaryValue* dict, | 233 // Checks that the usages ("use" and "key_ops") of the JWK is consistent with |
234 // "expected_usages". | |
235 Status VerifyUsages(const JwkReader& jwk, | |
381 blink::WebCryptoKeyUsageMask expected_usages) { | 236 blink::WebCryptoKeyUsageMask expected_usages) { |
382 // JWK "key_ops" (optional) --> usages parameter | 237 // JWK "key_ops" (optional) --> usages parameter |
383 base::ListValue* jwk_key_ops_value = NULL; | 238 base::ListValue* jwk_key_ops_value = NULL; |
384 bool has_jwk_key_ops; | 239 bool has_jwk_key_ops; |
385 Status status = | 240 Status status = |
386 GetOptionalJwkList(dict, "key_ops", &jwk_key_ops_value, &has_jwk_key_ops); | 241 jwk.GetOptionalList("key_ops", &jwk_key_ops_value, &has_jwk_key_ops); |
387 if (status.IsError()) | 242 if (status.IsError()) |
388 return status; | 243 return status; |
389 blink::WebCryptoKeyUsageMask jwk_key_ops_mask = 0; | 244 blink::WebCryptoKeyUsageMask jwk_key_ops_mask = 0; |
390 if (has_jwk_key_ops) { | 245 if (has_jwk_key_ops) { |
391 status = | 246 status = |
392 GetWebCryptoUsagesFromJwkKeyOps(jwk_key_ops_value, &jwk_key_ops_mask); | 247 GetWebCryptoUsagesFromJwkKeyOps(jwk_key_ops_value, &jwk_key_ops_mask); |
393 if (status.IsError()) | 248 if (status.IsError()) |
394 return status; | 249 return status; |
395 // The input usages must be a subset of jwk_key_ops_mask. | 250 // The input usages must be a subset of jwk_key_ops_mask. |
396 if (!ContainsKeyUsages(jwk_key_ops_mask, expected_usages)) | 251 if (!ContainsKeyUsages(jwk_key_ops_mask, expected_usages)) |
397 return Status::ErrorJwkKeyopsInconsistent(); | 252 return Status::ErrorJwkKeyopsInconsistent(); |
398 } | 253 } |
399 | 254 |
400 // JWK "use" (optional) --> usages parameter | 255 // JWK "use" (optional) --> usages parameter |
401 std::string jwk_use_value; | 256 std::string jwk_use_value; |
402 bool has_jwk_use; | 257 bool has_jwk_use; |
403 status = GetOptionalJwkString(dict, "use", &jwk_use_value, &has_jwk_use); | 258 status = jwk.GetOptionalString("use", &jwk_use_value, &has_jwk_use); |
404 if (status.IsError()) | 259 if (status.IsError()) |
405 return status; | 260 return status; |
406 blink::WebCryptoKeyUsageMask jwk_use_mask = 0; | 261 blink::WebCryptoKeyUsageMask jwk_use_mask = 0; |
407 if (has_jwk_use) { | 262 if (has_jwk_use) { |
408 if (jwk_use_value == "enc") | 263 if (jwk_use_value == "enc") |
409 jwk_use_mask = kJwkEncUsage; | 264 jwk_use_mask = kJwkEncUsage; |
410 else if (jwk_use_value == "sig") | 265 else if (jwk_use_value == "sig") |
411 jwk_use_mask = kJwkSigUsage; | 266 jwk_use_mask = kJwkSigUsage; |
412 else | 267 else |
413 return Status::ErrorJwkUnrecognizedUse(); | 268 return Status::ErrorJwkUnrecognizedUse(); |
414 // The input usages must be a subset of jwk_use_mask. | 269 // The input usages must be a subset of jwk_use_mask. |
415 if (!ContainsKeyUsages(jwk_use_mask, expected_usages)) | 270 if (!ContainsKeyUsages(jwk_use_mask, expected_usages)) |
416 return Status::ErrorJwkUseInconsistent(); | 271 return Status::ErrorJwkUseInconsistent(); |
417 } | 272 } |
418 | 273 |
419 // If both 'key_ops' and 'use' are present, ensure they are consistent. | 274 // If both 'key_ops' and 'use' are present, ensure they are consistent. |
420 if (has_jwk_key_ops && has_jwk_use && | 275 if (has_jwk_key_ops && has_jwk_use && |
421 !ContainsKeyUsages(jwk_use_mask, jwk_key_ops_mask)) | 276 !ContainsKeyUsages(jwk_use_mask, jwk_key_ops_mask)) |
422 return Status::ErrorJwkUseAndKeyopsInconsistent(); | 277 return Status::ErrorJwkUseAndKeyopsInconsistent(); |
423 | 278 |
424 return Status::Success(); | 279 return Status::Success(); |
425 } | 280 } |
426 | 281 |
427 Status VerifyAlg(base::DictionaryValue* dict, | 282 } // namespace |
eroman
2014/10/29 02:35:11
This was moved further down.
| |
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; | |
436 | 283 |
437 if (has_jwk_alg && jwk_alg_value != expected_algorithm) | 284 JwkReader::JwkReader() { |
438 return Status::ErrorJwkAlgorithmInconsistent(); | |
439 | |
440 return Status::Success(); | |
441 } | 285 } |
442 | 286 |
443 Status ParseJwkCommon(const CryptoData& bytes, | 287 JwkReader::~JwkReader() { |
444 bool expected_extractable, | 288 } |
445 blink::WebCryptoKeyUsageMask expected_usages, | 289 |
446 std::string* kty, | 290 Status JwkReader::Init(const CryptoData& bytes, |
447 scoped_ptr<base::DictionaryValue>* dict) { | 291 bool expected_extractable, |
292 blink::WebCryptoKeyUsageMask expected_usages, | |
293 const std::string& expected_kty) { | |
eroman
2014/10/29 02:35:11
Made 2 small changes here:
(1) Doesn't pass out
| |
294 if (!bytes.byte_length()) | |
295 return Status::ErrorImportEmptyKeyData(); | |
296 | |
448 // Parse the incoming JWK JSON. | 297 // Parse the incoming JWK JSON. |
449 base::StringPiece json_string(reinterpret_cast<const char*>(bytes.bytes()), | 298 base::StringPiece json_string(reinterpret_cast<const char*>(bytes.bytes()), |
450 bytes.byte_length()); | 299 bytes.byte_length()); |
451 | 300 |
452 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string)); | 301 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string)); |
453 base::DictionaryValue* dict_value = NULL; | 302 base::DictionaryValue* dict_value = NULL; |
454 | 303 |
455 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value) | 304 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value) |
456 return Status::ErrorJwkNotDictionary(); | 305 return Status::ErrorJwkNotDictionary(); |
457 | 306 |
458 // Release |value|, as ownership will be transferred to |dict| via | 307 // Release |value|, as ownership will be transferred to |dict| via |
459 // |dict_value|, which points to the same object as |value|. | 308 // |dict_value|, which points to the same object as |value|. |
460 ignore_result(value.release()); | 309 ignore_result(value.release()); |
461 dict->reset(dict_value); | 310 dict_.reset(dict_value); |
462 | 311 |
463 // JWK "kty". Exit early if this required JWK parameter is missing. | 312 // JWK "kty". Exit early if this required JWK parameter is missing. |
464 Status status = GetJwkString(dict_value, "kty", kty); | 313 std::string kty; |
314 Status status = GetString("kty", &kty); | |
465 if (status.IsError()) | 315 if (status.IsError()) |
466 return status; | 316 return status; |
467 | 317 |
468 status = VerifyExt(dict_value, expected_extractable); | 318 if (kty != expected_kty) |
319 return Status::ErrorJwkUnexpectedKty(expected_kty); | |
320 | |
321 status = VerifyExt(*this, expected_extractable); | |
469 if (status.IsError()) | 322 if (status.IsError()) |
470 return status; | 323 return status; |
471 | 324 |
472 status = VerifyUsages(dict_value, expected_usages); | 325 status = VerifyUsages(*this, expected_usages); |
473 if (status.IsError()) | 326 if (status.IsError()) |
474 return status; | 327 return status; |
475 | 328 |
476 return Status::Success(); | 329 return Status::Success(); |
477 } | 330 } |
478 | 331 |
332 bool JwkReader::HasKey(const std::string& key) const { | |
eroman
2014/10/29 02:35:11
This block of code was moved from above, to match
| |
333 return dict_->HasKey(key); | |
334 } | |
335 | |
336 Status JwkReader::GetString(const std::string& key, std::string* result) const { | |
337 base::Value* value = NULL; | |
338 if (!dict_->Get(key, &value)) | |
339 return Status::ErrorJwkPropertyMissing(key); | |
340 if (!value->GetAsString(result)) | |
341 return Status::ErrorJwkPropertyWrongType(key, "string"); | |
342 return Status::Success(); | |
343 } | |
344 | |
345 Status JwkReader::GetOptionalString(const std::string& key, | |
346 std::string* result, | |
347 bool* property_exists) const { | |
348 *property_exists = false; | |
349 base::Value* value = NULL; | |
350 if (!dict_->Get(key, &value)) | |
351 return Status::Success(); | |
352 | |
353 if (!value->GetAsString(result)) | |
354 return Status::ErrorJwkPropertyWrongType(key, "string"); | |
355 | |
356 *property_exists = true; | |
357 return Status::Success(); | |
358 } | |
359 | |
360 Status JwkReader::GetOptionalList(const std::string& key, | |
361 base::ListValue** result, | |
362 bool* property_exists) const { | |
363 *property_exists = false; | |
364 base::Value* value = NULL; | |
365 if (!dict_->Get(key, &value)) | |
366 return Status::Success(); | |
367 | |
368 if (!value->GetAsList(result)) | |
369 return Status::ErrorJwkPropertyWrongType(key, "list"); | |
370 | |
371 *property_exists = true; | |
372 return Status::Success(); | |
373 } | |
374 | |
375 Status JwkReader::GetBytes(const std::string& key, std::string* result) const { | |
376 std::string base64_string; | |
377 Status status = GetString(key, &base64_string); | |
378 if (status.IsError()) | |
379 return status; | |
380 | |
381 if (!Base64DecodeUrlSafe(base64_string, result)) | |
382 return Status::ErrorJwkBase64Decode(key); | |
383 | |
384 return Status::Success(); | |
385 } | |
386 | |
387 Status JwkReader::GetBigInteger(const std::string& key, | |
388 std::string* result) const { | |
389 Status status = GetBytes(key, result); | |
390 if (status.IsError()) | |
391 return status; | |
392 | |
393 if (result->empty()) | |
394 return Status::ErrorJwkEmptyBigInteger(key); | |
395 | |
396 // The JWA spec says that "The octet sequence MUST utilize the minimum number | |
397 // of octets to represent the value." This means there shouldn't be any | |
398 // leading zeros. | |
399 if (result->size() > 1 && (*result)[0] == 0) | |
400 return Status::ErrorJwkBigIntegerHasLeadingZero(key); | |
401 | |
402 return Status::Success(); | |
403 } | |
404 | |
405 Status JwkReader::GetOptionalBool(const std::string& key, | |
406 bool* result, | |
407 bool* property_exists) const { | |
408 *property_exists = false; | |
409 base::Value* value = NULL; | |
410 if (!dict_->Get(key, &value)) | |
411 return Status::Success(); | |
412 | |
413 if (!value->GetAsBoolean(result)) | |
414 return Status::ErrorJwkPropertyWrongType(key, "boolean"); | |
415 | |
416 *property_exists = true; | |
417 return Status::Success(); | |
418 } | |
419 | |
420 Status JwkReader::VerifyAlg(const std::string& expected_algorithm) const { | |
421 bool has_jwk_alg; | |
422 std::string jwk_alg_value; | |
423 Status status = GetOptionalString("alg", &jwk_alg_value, &has_jwk_alg); | |
424 if (status.IsError()) | |
425 return status; | |
426 | |
427 if (has_jwk_alg && jwk_alg_value != expected_algorithm) | |
428 return Status::ErrorJwkAlgorithmInconsistent(); | |
429 | |
430 return Status::Success(); | |
431 } | |
432 | |
433 JwkWriter::JwkWriter(const std::string& algorithm, | |
434 bool extractable, | |
435 blink::WebCryptoKeyUsageMask usages, | |
436 const std::string& kty) { | |
437 dict_.SetString("alg", algorithm); | |
438 dict_.Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(usages)); | |
439 dict_.SetBoolean("ext", extractable); | |
440 dict_.SetString("kty", kty); | |
441 } | |
442 | |
443 void JwkWriter::SetString(const std::string& key, const std::string& value) { | |
444 dict_.SetString(key, value); | |
445 } | |
446 | |
447 void JwkWriter::SetBytes(const std::string& key, const CryptoData& value) { | |
448 dict_.SetString( | |
449 key, | |
450 Base64EncodeUrlSafe(base::StringPiece( | |
451 reinterpret_cast<const char*>(value.bytes()), value.byte_length()))); | |
452 } | |
453 | |
454 void JwkWriter::ToJson(std::vector<uint8_t>* utf8_bytes) const { | |
455 std::string json; | |
456 base::JSONWriter::Write(&dict_, &json); | |
457 utf8_bytes->assign(json.begin(), json.end()); | |
458 } | |
459 | |
479 Status ReadSecretKeyNoExpectedAlg(const CryptoData& key_data, | 460 Status ReadSecretKeyNoExpectedAlg(const CryptoData& key_data, |
480 bool expected_extractable, | 461 bool expected_extractable, |
481 blink::WebCryptoKeyUsageMask expected_usages, | 462 blink::WebCryptoKeyUsageMask expected_usages, |
482 std::vector<uint8_t>* raw_key_data, | 463 std::vector<uint8_t>* raw_key_data, |
483 scoped_ptr<base::DictionaryValue>* dict) { | 464 JwkReader* jwk) { |
484 if (!key_data.byte_length()) | 465 Status status = |
485 return Status::ErrorImportEmptyKeyData(); | 466 jwk->Init(key_data, expected_extractable, expected_usages, "oct"); |
486 | |
487 std::string kty; | |
488 Status status = ParseJwkCommon( | |
489 key_data, expected_extractable, expected_usages, &kty, dict); | |
490 if (status.IsError()) | 467 if (status.IsError()) |
491 return status; | 468 return status; |
492 | 469 |
493 if (kty != "oct") | |
494 return Status::ErrorJwkUnexpectedKty("oct"); | |
495 | |
496 std::string jwk_k_value; | 470 std::string jwk_k_value; |
497 status = GetJwkBytes(dict->get(), "k", &jwk_k_value); | 471 status = jwk->GetBytes("k", &jwk_k_value); |
498 if (status.IsError()) | 472 if (status.IsError()) |
499 return status; | 473 return status; |
500 raw_key_data->assign(jwk_k_value.begin(), jwk_k_value.end()); | 474 raw_key_data->assign(jwk_k_value.begin(), jwk_k_value.end()); |
501 | 475 |
502 return Status::Success(); | 476 return Status::Success(); |
503 } | 477 } |
504 | 478 |
505 } // namespace | |
506 | |
507 void WriteSecretKeyJwk(const CryptoData& raw_key_data, | 479 void WriteSecretKeyJwk(const CryptoData& raw_key_data, |
508 const std::string& algorithm, | 480 const std::string& algorithm, |
509 bool extractable, | 481 bool extractable, |
510 blink::WebCryptoKeyUsageMask usages, | 482 blink::WebCryptoKeyUsageMask usages, |
511 std::vector<uint8_t>* jwk_key_data) { | 483 std::vector<uint8_t>* jwk_key_data) { |
512 JwkWriter writer(algorithm, extractable, usages, "oct"); | 484 JwkWriter writer(algorithm, extractable, usages, "oct"); |
513 writer.SetBase64Encoded("k", raw_key_data); | 485 writer.SetBytes("k", raw_key_data); |
514 writer.ToBytes(jwk_key_data); | 486 writer.ToJson(jwk_key_data); |
515 } | 487 } |
516 | 488 |
517 Status ReadSecretKeyJwk(const CryptoData& key_data, | 489 Status ReadSecretKeyJwk(const CryptoData& key_data, |
518 const std::string& expected_algorithm, | 490 const std::string& expected_algorithm, |
519 bool expected_extractable, | 491 bool expected_extractable, |
520 blink::WebCryptoKeyUsageMask expected_usages, | 492 blink::WebCryptoKeyUsageMask expected_usages, |
521 std::vector<uint8_t>* raw_key_data) { | 493 std::vector<uint8_t>* raw_key_data) { |
522 scoped_ptr<base::DictionaryValue> dict; | 494 JwkReader jwk; |
523 Status status = ReadSecretKeyNoExpectedAlg( | 495 Status status = ReadSecretKeyNoExpectedAlg( |
524 key_data, expected_extractable, expected_usages, raw_key_data, &dict); | 496 key_data, expected_extractable, expected_usages, raw_key_data, &jwk); |
525 if (status.IsError()) | 497 if (status.IsError()) |
526 return status; | 498 return status; |
527 return VerifyAlg(dict.get(), expected_algorithm); | 499 return jwk.VerifyAlg(expected_algorithm); |
528 } | 500 } |
529 | 501 |
530 std::string MakeJwkAesAlgorithmName(const std::string& suffix, | 502 std::string MakeJwkAesAlgorithmName(const std::string& suffix, |
531 unsigned int keylen_bytes) { | 503 unsigned int keylen_bytes) { |
532 if (keylen_bytes == 16) | 504 if (keylen_bytes == 16) |
533 return std::string("A128") + suffix; | 505 return std::string("A128") + suffix; |
534 if (keylen_bytes == 24) | 506 if (keylen_bytes == 24) |
535 return std::string("A192") + suffix; | 507 return std::string("A192") + suffix; |
536 if (keylen_bytes == 32) | 508 if (keylen_bytes == 32) |
537 return std::string("A256") + suffix; | 509 return std::string("A256") + suffix; |
538 return std::string(); | 510 return std::string(); |
539 } | 511 } |
540 | 512 |
541 Status ReadAesSecretKeyJwk(const CryptoData& key_data, | 513 Status ReadAesSecretKeyJwk(const CryptoData& key_data, |
542 const std::string& algorithm_name_suffix, | 514 const std::string& algorithm_name_suffix, |
543 bool expected_extractable, | 515 bool expected_extractable, |
544 blink::WebCryptoKeyUsageMask expected_usages, | 516 blink::WebCryptoKeyUsageMask expected_usages, |
545 std::vector<uint8_t>* raw_key_data) { | 517 std::vector<uint8_t>* raw_key_data) { |
546 scoped_ptr<base::DictionaryValue> dict; | 518 JwkReader jwk; |
547 Status status = ReadSecretKeyNoExpectedAlg( | 519 Status status = ReadSecretKeyNoExpectedAlg( |
548 key_data, expected_extractable, expected_usages, raw_key_data, &dict); | 520 key_data, expected_extractable, expected_usages, raw_key_data, &jwk); |
549 if (status.IsError()) | 521 if (status.IsError()) |
550 return status; | 522 return status; |
551 | 523 |
552 bool has_jwk_alg; | 524 bool has_jwk_alg; |
553 std::string jwk_alg; | 525 std::string jwk_alg; |
554 status = GetOptionalJwkString(dict.get(), "alg", &jwk_alg, &has_jwk_alg); | 526 status = jwk.GetOptionalString("alg", &jwk_alg, &has_jwk_alg); |
555 if (status.IsError()) | 527 if (status.IsError()) |
556 return status; | 528 return status; |
557 | 529 |
558 if (has_jwk_alg) { | 530 if (has_jwk_alg) { |
559 std::string expected_algorithm_name = | 531 std::string expected_algorithm_name = |
560 MakeJwkAesAlgorithmName(algorithm_name_suffix, raw_key_data->size()); | 532 MakeJwkAesAlgorithmName(algorithm_name_suffix, raw_key_data->size()); |
561 | 533 |
562 if (jwk_alg != expected_algorithm_name) { | 534 if (jwk_alg != expected_algorithm_name) { |
563 // Give a different error message if the key length was wrong. | 535 // Give a different error message if the key length was wrong. |
564 if (jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 16) || | 536 if (jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 16) || |
565 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 24) || | 537 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 24) || |
566 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 32)) { | 538 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 32)) { |
567 return Status::ErrorJwkIncorrectKeyLength(); | 539 return Status::ErrorJwkIncorrectKeyLength(); |
568 } | 540 } |
569 return Status::ErrorJwkAlgorithmInconsistent(); | 541 return Status::ErrorJwkAlgorithmInconsistent(); |
570 } | 542 } |
571 } | 543 } |
572 | 544 |
573 return Status::Success(); | 545 return Status::Success(); |
574 } | 546 } |
575 | 547 |
576 // Writes an RSA public key to a JWK dictionary | 548 // Writes an RSA public key to a JWK dictionary |
577 void WriteRsaPublicKeyJwk(const CryptoData& n, | 549 void WriteRsaPublicKeyJwk(const CryptoData& n, |
578 const CryptoData& e, | 550 const CryptoData& e, |
579 const std::string& algorithm, | 551 const std::string& algorithm, |
580 bool extractable, | 552 bool extractable, |
581 blink::WebCryptoKeyUsageMask usages, | 553 blink::WebCryptoKeyUsageMask usages, |
582 std::vector<uint8_t>* jwk_key_data) { | 554 std::vector<uint8_t>* jwk_key_data) { |
583 JwkWriter writer(algorithm, extractable, usages, "RSA"); | 555 JwkWriter writer(algorithm, extractable, usages, "RSA"); |
584 writer.SetBase64Encoded("n", n); | 556 writer.SetBytes("n", n); |
585 writer.SetBase64Encoded("e", e); | 557 writer.SetBytes("e", e); |
586 writer.ToBytes(jwk_key_data); | 558 writer.ToJson(jwk_key_data); |
587 } | 559 } |
588 | 560 |
589 // Writes an RSA private key to a JWK dictionary | 561 // Writes an RSA private key to a JWK dictionary |
590 void WriteRsaPrivateKeyJwk(const CryptoData& n, | 562 void WriteRsaPrivateKeyJwk(const CryptoData& n, |
591 const CryptoData& e, | 563 const CryptoData& e, |
592 const CryptoData& d, | 564 const CryptoData& d, |
593 const CryptoData& p, | 565 const CryptoData& p, |
594 const CryptoData& q, | 566 const CryptoData& q, |
595 const CryptoData& dp, | 567 const CryptoData& dp, |
596 const CryptoData& dq, | 568 const CryptoData& dq, |
597 const CryptoData& qi, | 569 const CryptoData& qi, |
598 const std::string& algorithm, | 570 const std::string& algorithm, |
599 bool extractable, | 571 bool extractable, |
600 blink::WebCryptoKeyUsageMask usages, | 572 blink::WebCryptoKeyUsageMask usages, |
601 std::vector<uint8_t>* jwk_key_data) { | 573 std::vector<uint8_t>* jwk_key_data) { |
602 JwkWriter writer(algorithm, extractable, usages, "RSA"); | 574 JwkWriter writer(algorithm, extractable, usages, "RSA"); |
603 | 575 |
604 writer.SetBase64Encoded("n", n); | 576 writer.SetBytes("n", n); |
605 writer.SetBase64Encoded("e", e); | 577 writer.SetBytes("e", e); |
606 writer.SetBase64Encoded("d", d); | 578 writer.SetBytes("d", d); |
607 // Although these are "optional" in the JWA, WebCrypto spec requires them to | 579 // Although these are "optional" in the JWA, WebCrypto spec requires them to |
608 // be emitted. | 580 // be emitted. |
609 writer.SetBase64Encoded("p", p); | 581 writer.SetBytes("p", p); |
610 writer.SetBase64Encoded("q", q); | 582 writer.SetBytes("q", q); |
611 writer.SetBase64Encoded("dp", dp); | 583 writer.SetBytes("dp", dp); |
612 writer.SetBase64Encoded("dq", dq); | 584 writer.SetBytes("dq", dq); |
613 writer.SetBase64Encoded("qi", qi); | 585 writer.SetBytes("qi", qi); |
614 writer.ToBytes(jwk_key_data); | 586 writer.ToJson(jwk_key_data); |
615 } | 587 } |
616 | 588 |
617 JwkRsaInfo::JwkRsaInfo() : is_private_key(false) { | 589 JwkRsaInfo::JwkRsaInfo() : is_private_key(false) { |
618 } | 590 } |
619 | 591 |
620 JwkRsaInfo::~JwkRsaInfo() { | 592 JwkRsaInfo::~JwkRsaInfo() { |
621 } | 593 } |
622 | 594 |
623 Status ReadRsaKeyJwk(const CryptoData& key_data, | 595 Status ReadRsaKeyJwk(const CryptoData& key_data, |
624 const std::string& expected_algorithm, | 596 const std::string& expected_algorithm, |
625 bool expected_extractable, | 597 bool expected_extractable, |
626 blink::WebCryptoKeyUsageMask expected_usages, | 598 blink::WebCryptoKeyUsageMask expected_usages, |
627 JwkRsaInfo* result) { | 599 JwkRsaInfo* result) { |
628 if (!key_data.byte_length()) | 600 JwkReader jwk; |
629 return Status::ErrorImportEmptyKeyData(); | 601 Status status = |
630 | 602 jwk.Init(key_data, expected_extractable, expected_usages, "RSA"); |
631 scoped_ptr<base::DictionaryValue> dict; | |
632 std::string kty; | |
633 Status status = ParseJwkCommon( | |
634 key_data, expected_extractable, expected_usages, &kty, &dict); | |
635 if (status.IsError()) | 603 if (status.IsError()) |
636 return status; | 604 return status; |
637 | 605 |
638 status = VerifyAlg(dict.get(), expected_algorithm); | 606 status = jwk.VerifyAlg(expected_algorithm); |
639 if (status.IsError()) | 607 if (status.IsError()) |
640 return status; | 608 return status; |
641 | 609 |
642 if (kty != "RSA") | |
643 return Status::ErrorJwkUnexpectedKty("RSA"); | |
644 | |
645 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry | 610 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry |
646 // in the JWK, while an RSA private key must have those, plus at least a "d" | 611 // in the JWK, while an RSA private key must have those, plus at least a "d" |
647 // (private exponent) entry. | 612 // (private exponent) entry. |
648 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18, | 613 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18, |
649 // section 6.3. | 614 // section 6.3. |
650 status = GetJwkBigInteger(dict.get(), "n", &result->n); | 615 status = jwk.GetBigInteger("n", &result->n); |
651 if (status.IsError()) | 616 if (status.IsError()) |
652 return status; | 617 return status; |
653 status = GetJwkBigInteger(dict.get(), "e", &result->e); | 618 status = jwk.GetBigInteger("e", &result->e); |
654 if (status.IsError()) | 619 if (status.IsError()) |
655 return status; | 620 return status; |
656 | 621 |
657 result->is_private_key = dict->HasKey("d"); | 622 result->is_private_key = jwk.HasKey("d"); |
658 if (!result->is_private_key) | 623 if (!result->is_private_key) |
659 return Status::Success(); | 624 return Status::Success(); |
660 | 625 |
661 status = GetJwkBigInteger(dict.get(), "d", &result->d); | 626 status = jwk.GetBigInteger("d", &result->d); |
662 if (status.IsError()) | 627 if (status.IsError()) |
663 return status; | 628 return status; |
664 | 629 |
665 // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA | 630 // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA |
666 // spec. However they are required by Chromium's WebCrypto implementation. | 631 // spec. However they are required by Chromium's WebCrypto implementation. |
667 | 632 |
668 status = GetJwkBigInteger(dict.get(), "p", &result->p); | 633 status = jwk.GetBigInteger("p", &result->p); |
669 if (status.IsError()) | 634 if (status.IsError()) |
670 return status; | 635 return status; |
671 | 636 |
672 status = GetJwkBigInteger(dict.get(), "q", &result->q); | 637 status = jwk.GetBigInteger("q", &result->q); |
673 if (status.IsError()) | 638 if (status.IsError()) |
674 return status; | 639 return status; |
675 | 640 |
676 status = GetJwkBigInteger(dict.get(), "dp", &result->dp); | 641 status = jwk.GetBigInteger("dp", &result->dp); |
677 if (status.IsError()) | 642 if (status.IsError()) |
678 return status; | 643 return status; |
679 | 644 |
680 status = GetJwkBigInteger(dict.get(), "dq", &result->dq); | 645 status = jwk.GetBigInteger("dq", &result->dq); |
681 if (status.IsError()) | 646 if (status.IsError()) |
682 return status; | 647 return status; |
683 | 648 |
684 status = GetJwkBigInteger(dict.get(), "qi", &result->qi); | 649 status = jwk.GetBigInteger("qi", &result->qi); |
685 if (status.IsError()) | 650 if (status.IsError()) |
686 return status; | 651 return status; |
687 | 652 |
688 return Status::Success(); | 653 return Status::Success(); |
689 } | 654 } |
690 | 655 |
691 const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) { | 656 const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) { |
692 switch (hash) { | 657 switch (hash) { |
693 case blink::WebCryptoAlgorithmIdSha1: | 658 case blink::WebCryptoAlgorithmIdSha1: |
694 return "HS1"; | 659 return "HS1"; |
(...skipping 30 matching lines...) Expand all Loading... | |
725 | 690 |
726 std::string Base64EncodeUrlSafe(const std::vector<uint8_t>& input) { | 691 std::string Base64EncodeUrlSafe(const std::vector<uint8_t>& input) { |
727 const base::StringPiece string_piece( | 692 const base::StringPiece string_piece( |
728 reinterpret_cast<const char*>(vector_as_array(&input)), input.size()); | 693 reinterpret_cast<const char*>(vector_as_array(&input)), input.size()); |
729 return Base64EncodeUrlSafe(string_piece); | 694 return Base64EncodeUrlSafe(string_piece); |
730 } | 695 } |
731 | 696 |
732 } // namespace webcrypto | 697 } // namespace webcrypto |
733 | 698 |
734 } // namespace content | 699 } // namespace content |
OLD | NEW |