OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "content/renderer/webcrypto/webcrypto_impl.h" | 5 #include "content/renderer/webcrypto/webcrypto_impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <functional> | 8 #include <functional> |
9 #include <map> | 9 #include <map> |
10 #include "base/json/json_reader.h" | 10 #include "base/json/json_reader.h" |
11 #include "base/lazy_instance.h" | 11 #include "base/lazy_instance.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
14 #include "base/strings/string_piece.h" | 14 #include "base/strings/string_piece.h" |
15 #include "base/values.h" | 15 #include "base/values.h" |
16 #include "content/renderer/webcrypto/webcrypto_util.h" | |
17 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 16 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
18 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | 17 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |
19 #include "third_party/WebKit/public/platform/WebCryptoKey.h" | 18 #include "third_party/WebKit/public/platform/WebCryptoKey.h" |
19 #include "third_party/WebKit/public/platform/WebString.h" | |
20 | 20 |
21 namespace content { | 21 namespace content { |
22 | 22 |
23 using webcrypto::Status; | |
24 | |
23 namespace { | 25 namespace { |
24 | 26 |
27 void CompleteWithError(const Status& status, blink::WebCryptoResult* result) { | |
28 DCHECK(status.IsError()); | |
29 result->completeWithError(blink::WebString::fromUTF8(status.ToString())); | |
30 } | |
31 | |
25 bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { | 32 bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { |
26 // TODO(padolph): include all other asymmetric algorithms once they are | 33 // TODO(padolph): include all other asymmetric algorithms once they are |
27 // defined, e.g. EC and DH. | 34 // defined, e.g. EC and DH. |
28 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || | 35 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || |
29 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || | 36 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || |
30 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep); | 37 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep); |
31 } | 38 } |
32 | 39 |
33 // Binds a specific key length value to a compatible factory function. | 40 // Binds a specific key length value to a compatible factory function. |
34 typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithOneShortArg)( | 41 typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithOneShortArg)( |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
168 } | 175 } |
169 | 176 |
170 void WebCryptoImpl::encrypt( | 177 void WebCryptoImpl::encrypt( |
171 const blink::WebCryptoAlgorithm& algorithm, | 178 const blink::WebCryptoAlgorithm& algorithm, |
172 const blink::WebCryptoKey& key, | 179 const blink::WebCryptoKey& key, |
173 const unsigned char* data, | 180 const unsigned char* data, |
174 unsigned data_size, | 181 unsigned data_size, |
175 blink::WebCryptoResult result) { | 182 blink::WebCryptoResult result) { |
176 DCHECK(!algorithm.isNull()); | 183 DCHECK(!algorithm.isNull()); |
177 blink::WebArrayBuffer buffer; | 184 blink::WebArrayBuffer buffer; |
178 if (!EncryptInternal(algorithm, key, data, data_size, &buffer)) { | 185 Status status = EncryptInternal(algorithm, key, data, data_size, &buffer); |
179 result.completeWithError(); | 186 if (status.IsError()) { |
187 CompleteWithError(status, &result); | |
Ryan Sleevi
2014/01/28 21:11:58
Does it make sense for this pattern to follow the
eroman
2014/01/28 22:59:08
I personally like early return code and would be i
| |
180 } else { | 188 } else { |
181 result.completeWithBuffer(buffer); | 189 result.completeWithBuffer(buffer); |
182 } | 190 } |
183 } | 191 } |
184 | 192 |
185 void WebCryptoImpl::decrypt( | 193 void WebCryptoImpl::decrypt( |
186 const blink::WebCryptoAlgorithm& algorithm, | 194 const blink::WebCryptoAlgorithm& algorithm, |
187 const blink::WebCryptoKey& key, | 195 const blink::WebCryptoKey& key, |
188 const unsigned char* data, | 196 const unsigned char* data, |
189 unsigned data_size, | 197 unsigned data_size, |
190 blink::WebCryptoResult result) { | 198 blink::WebCryptoResult result) { |
191 DCHECK(!algorithm.isNull()); | 199 DCHECK(!algorithm.isNull()); |
192 blink::WebArrayBuffer buffer; | 200 blink::WebArrayBuffer buffer; |
193 if (!DecryptInternal(algorithm, key, data, data_size, &buffer)) { | 201 Status status = DecryptInternal(algorithm, key, data, data_size, &buffer); |
194 result.completeWithError(); | 202 if (status.IsError()) { |
203 CompleteWithError(status, &result); | |
195 } else { | 204 } else { |
196 result.completeWithBuffer(buffer); | 205 result.completeWithBuffer(buffer); |
197 } | 206 } |
198 } | 207 } |
199 | 208 |
200 void WebCryptoImpl::digest( | 209 void WebCryptoImpl::digest( |
201 const blink::WebCryptoAlgorithm& algorithm, | 210 const blink::WebCryptoAlgorithm& algorithm, |
202 const unsigned char* data, | 211 const unsigned char* data, |
203 unsigned data_size, | 212 unsigned data_size, |
204 blink::WebCryptoResult result) { | 213 blink::WebCryptoResult result) { |
205 DCHECK(!algorithm.isNull()); | 214 DCHECK(!algorithm.isNull()); |
206 blink::WebArrayBuffer buffer; | 215 blink::WebArrayBuffer buffer; |
207 if (!DigestInternal(algorithm, data, data_size, &buffer)) { | 216 Status status = DigestInternal(algorithm, data, data_size, &buffer); |
208 result.completeWithError(); | 217 if (status.IsError()) { |
218 CompleteWithError(status, &result); | |
209 } else { | 219 } else { |
210 result.completeWithBuffer(buffer); | 220 result.completeWithBuffer(buffer); |
211 } | 221 } |
212 } | 222 } |
213 | 223 |
214 void WebCryptoImpl::generateKey( | 224 void WebCryptoImpl::generateKey( |
215 const blink::WebCryptoAlgorithm& algorithm, | 225 const blink::WebCryptoAlgorithm& algorithm, |
216 bool extractable, | 226 bool extractable, |
217 blink::WebCryptoKeyUsageMask usage_mask, | 227 blink::WebCryptoKeyUsageMask usage_mask, |
218 blink::WebCryptoResult result) { | 228 blink::WebCryptoResult result) { |
219 DCHECK(!algorithm.isNull()); | 229 DCHECK(!algorithm.isNull()); |
220 if (IsAlgorithmAsymmetric(algorithm)) { | 230 if (IsAlgorithmAsymmetric(algorithm)) { |
221 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); | 231 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); |
222 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); | 232 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); |
223 if (!GenerateKeyPairInternal( | 233 Status status = GenerateKeyPairInternal( |
224 algorithm, extractable, usage_mask, &public_key, &private_key)) { | 234 algorithm, extractable, usage_mask, &public_key, &private_key); |
225 result.completeWithError(); | 235 if (status.IsError()) { |
236 CompleteWithError(status, &result); | |
226 } else { | 237 } else { |
227 DCHECK(public_key.handle()); | 238 DCHECK(public_key.handle()); |
228 DCHECK(private_key.handle()); | 239 DCHECK(private_key.handle()); |
229 DCHECK_EQ(algorithm.id(), public_key.algorithm().id()); | 240 DCHECK_EQ(algorithm.id(), public_key.algorithm().id()); |
230 DCHECK_EQ(algorithm.id(), private_key.algorithm().id()); | 241 DCHECK_EQ(algorithm.id(), private_key.algorithm().id()); |
231 DCHECK_EQ(true, public_key.extractable()); | 242 DCHECK_EQ(true, public_key.extractable()); |
232 DCHECK_EQ(extractable, private_key.extractable()); | 243 DCHECK_EQ(extractable, private_key.extractable()); |
233 DCHECK_EQ(usage_mask, public_key.usages()); | 244 DCHECK_EQ(usage_mask, public_key.usages()); |
234 DCHECK_EQ(usage_mask, private_key.usages()); | 245 DCHECK_EQ(usage_mask, private_key.usages()); |
235 result.completeWithKeyPair(public_key, private_key); | 246 result.completeWithKeyPair(public_key, private_key); |
236 } | 247 } |
237 } else { | 248 } else { |
238 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 249 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
239 if (!GenerateKeyInternal(algorithm, extractable, usage_mask, &key)) { | 250 Status status = GenerateKeyInternal( |
240 result.completeWithError(); | 251 algorithm, extractable, usage_mask, &key); |
252 if (status.IsError()) { | |
253 CompleteWithError(status, &result); | |
241 } else { | 254 } else { |
242 DCHECK(key.handle()); | 255 DCHECK(key.handle()); |
243 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | 256 DCHECK_EQ(algorithm.id(), key.algorithm().id()); |
244 DCHECK_EQ(extractable, key.extractable()); | 257 DCHECK_EQ(extractable, key.extractable()); |
245 DCHECK_EQ(usage_mask, key.usages()); | 258 DCHECK_EQ(usage_mask, key.usages()); |
246 result.completeWithKey(key); | 259 result.completeWithKey(key); |
247 } | 260 } |
248 } | 261 } |
249 } | 262 } |
250 | 263 |
251 void WebCryptoImpl::importKey( | 264 void WebCryptoImpl::importKey( |
252 blink::WebCryptoKeyFormat format, | 265 blink::WebCryptoKeyFormat format, |
253 const unsigned char* key_data, | 266 const unsigned char* key_data, |
254 unsigned key_data_size, | 267 unsigned key_data_size, |
255 const blink::WebCryptoAlgorithm& algorithm_or_null, | 268 const blink::WebCryptoAlgorithm& algorithm_or_null, |
256 bool extractable, | 269 bool extractable, |
257 blink::WebCryptoKeyUsageMask usage_mask, | 270 blink::WebCryptoKeyUsageMask usage_mask, |
258 blink::WebCryptoResult result) { | 271 blink::WebCryptoResult result) { |
259 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 272 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
273 Status status = Status::Error(); | |
260 if (format == blink::WebCryptoKeyFormatJwk) { | 274 if (format == blink::WebCryptoKeyFormatJwk) { |
261 if (!ImportKeyJwk(key_data, | 275 status = ImportKeyJwk(key_data, |
262 key_data_size, | 276 key_data_size, |
263 algorithm_or_null, | 277 algorithm_or_null, |
264 extractable, | 278 extractable, |
265 usage_mask, | 279 usage_mask, |
266 &key)) { | 280 &key); |
267 result.completeWithError(); | |
268 return; | |
269 } | |
270 } else { | 281 } else { |
271 if (!ImportKeyInternal(format, | 282 status = ImportKeyInternal(format, |
272 key_data, | 283 key_data, |
273 key_data_size, | 284 key_data_size, |
274 algorithm_or_null, | 285 algorithm_or_null, |
275 extractable, | 286 extractable, |
276 usage_mask, | 287 usage_mask, |
277 &key)) { | 288 &key); |
278 result.completeWithError(); | |
279 return; | |
280 } | |
281 } | 289 } |
282 DCHECK(key.handle()); | 290 if (status.IsError()) { |
283 DCHECK(!key.algorithm().isNull()); | 291 CompleteWithError(status, &result); |
284 DCHECK_EQ(extractable, key.extractable()); | 292 } else { |
285 result.completeWithKey(key); | 293 DCHECK(key.handle()); |
294 DCHECK(!key.algorithm().isNull()); | |
295 DCHECK_EQ(extractable, key.extractable()); | |
296 result.completeWithKey(key); | |
297 } | |
286 } | 298 } |
287 | 299 |
288 void WebCryptoImpl::exportKey( | 300 void WebCryptoImpl::exportKey( |
289 blink::WebCryptoKeyFormat format, | 301 blink::WebCryptoKeyFormat format, |
290 const blink::WebCryptoKey& key, | 302 const blink::WebCryptoKey& key, |
291 blink::WebCryptoResult result) { | 303 blink::WebCryptoResult result) { |
292 blink::WebArrayBuffer buffer; | 304 blink::WebArrayBuffer buffer; |
293 if (!ExportKeyInternal(format, key, &buffer)) { | 305 Status status = ExportKeyInternal(format, key, &buffer); |
294 result.completeWithError(); | 306 if (status.IsError()) { |
295 return; | 307 CompleteWithError(status, &result); |
308 } else { | |
309 result.completeWithBuffer(buffer); | |
296 } | 310 } |
297 result.completeWithBuffer(buffer); | |
298 } | 311 } |
299 | 312 |
300 void WebCryptoImpl::sign( | 313 void WebCryptoImpl::sign( |
301 const blink::WebCryptoAlgorithm& algorithm, | 314 const blink::WebCryptoAlgorithm& algorithm, |
302 const blink::WebCryptoKey& key, | 315 const blink::WebCryptoKey& key, |
303 const unsigned char* data, | 316 const unsigned char* data, |
304 unsigned data_size, | 317 unsigned data_size, |
305 blink::WebCryptoResult result) { | 318 blink::WebCryptoResult result) { |
306 DCHECK(!algorithm.isNull()); | 319 DCHECK(!algorithm.isNull()); |
307 blink::WebArrayBuffer buffer; | 320 blink::WebArrayBuffer buffer; |
308 if (!SignInternal(algorithm, key, data, data_size, &buffer)) { | 321 Status status = SignInternal(algorithm, key, data, data_size, &buffer); |
309 result.completeWithError(); | 322 if (status.IsError()) { |
323 CompleteWithError(status, &result); | |
310 } else { | 324 } else { |
311 result.completeWithBuffer(buffer); | 325 result.completeWithBuffer(buffer); |
312 } | 326 } |
313 } | 327 } |
314 | 328 |
315 void WebCryptoImpl::verifySignature( | 329 void WebCryptoImpl::verifySignature( |
316 const blink::WebCryptoAlgorithm& algorithm, | 330 const blink::WebCryptoAlgorithm& algorithm, |
317 const blink::WebCryptoKey& key, | 331 const blink::WebCryptoKey& key, |
318 const unsigned char* signature, | 332 const unsigned char* signature, |
319 unsigned signature_size, | 333 unsigned signature_size, |
320 const unsigned char* data, | 334 const unsigned char* data, |
321 unsigned data_size, | 335 unsigned data_size, |
322 blink::WebCryptoResult result) { | 336 blink::WebCryptoResult result) { |
323 DCHECK(!algorithm.isNull()); | 337 DCHECK(!algorithm.isNull()); |
324 bool signature_match = false; | 338 bool signature_match = false; |
325 if (!VerifySignatureInternal(algorithm, | 339 Status status = VerifySignatureInternal(algorithm, |
326 key, | 340 key, |
327 signature, | 341 signature, |
328 signature_size, | 342 signature_size, |
329 data, | 343 data, |
330 data_size, | 344 data_size, |
331 &signature_match)) { | 345 &signature_match); |
332 result.completeWithError(); | 346 if (status.IsError()) { |
347 CompleteWithError(status, &result); | |
333 } else { | 348 } else { |
334 result.completeWithBoolean(signature_match); | 349 result.completeWithBoolean(signature_match); |
335 } | 350 } |
336 } | 351 } |
337 | 352 |
338 bool WebCryptoImpl::ImportKeyJwk( | 353 Status WebCryptoImpl::ImportKeyJwk( |
339 const unsigned char* key_data, | 354 const unsigned char* key_data, |
340 unsigned key_data_size, | 355 unsigned key_data_size, |
341 const blink::WebCryptoAlgorithm& algorithm_or_null, | 356 const blink::WebCryptoAlgorithm& algorithm_or_null, |
342 bool extractable, | 357 bool extractable, |
343 blink::WebCryptoKeyUsageMask usage_mask, | 358 blink::WebCryptoKeyUsageMask usage_mask, |
344 blink::WebCryptoKey* key) { | 359 blink::WebCryptoKey* key) { |
345 | 360 |
346 // The goal of this method is to extract key material and meta data from the | 361 // The goal of this method is to extract key material and meta data from the |
347 // incoming JWK, combine them with the input parameters, and ultimately import | 362 // incoming JWK, combine them with the input parameters, and ultimately import |
348 // a Web Crypto Key. | 363 // a Web Crypto Key. |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
472 // false but the input parameter is true, it is an inconsistency. If both | 487 // false but the input parameter is true, it is an inconsistency. If both |
473 // are true or both are false, use that value. | 488 // are true or both are false, use that value. |
474 // | 489 // |
475 // usage_mask | 490 // usage_mask |
476 // The input usage_mask must be a strict subset of the interpreted JWK use | 491 // The input usage_mask must be a strict subset of the interpreted JWK use |
477 // value, else it is judged inconsistent. In all cases the input usage_mask | 492 // value, else it is judged inconsistent. In all cases the input usage_mask |
478 // is used as the final usage_mask. | 493 // is used as the final usage_mask. |
479 // | 494 // |
480 | 495 |
481 if (!key_data_size) | 496 if (!key_data_size) |
482 return false; | 497 return Status::ErrorImportEmptyKeyData(); |
483 DCHECK(key); | 498 DCHECK(key); |
484 | 499 |
485 // Parse the incoming JWK JSON. | 500 // Parse the incoming JWK JSON. |
486 base::StringPiece json_string(reinterpret_cast<const char*>(key_data), | 501 base::StringPiece json_string(reinterpret_cast<const char*>(key_data), |
487 key_data_size); | 502 key_data_size); |
488 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string)); | 503 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string)); |
489 // Note, bare pointer dict_value is ok since it points into scoped value. | 504 // Note, bare pointer dict_value is ok since it points into scoped value. |
490 base::DictionaryValue* dict_value = NULL; | 505 base::DictionaryValue* dict_value = NULL; |
491 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value) | 506 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value) |
492 return false; | 507 return Status::ErrorJwkNotDictionary(); |
493 | 508 |
494 // JWK "kty". Exit early if this required JWK parameter is missing. | 509 // JWK "kty". Exit early if this required JWK parameter is missing. |
495 std::string jwk_kty_value; | 510 std::string jwk_kty_value; |
496 if (!dict_value->GetString("kty", &jwk_kty_value)) | 511 if (!dict_value->GetString("kty", &jwk_kty_value)) |
497 return false; | 512 return Status::ErrorJwkMissingKty(); |
498 | 513 |
499 // JWK "extractable" (optional) --> extractable parameter | 514 // JWK "extractable" (optional) --> extractable parameter |
500 { | 515 { |
501 bool jwk_extractable_value; | 516 bool jwk_extractable_value; |
502 if (dict_value->GetBoolean("extractable", &jwk_extractable_value)) { | 517 if (dict_value->GetBoolean("extractable", &jwk_extractable_value)) { |
503 if (!jwk_extractable_value && extractable) | 518 if (!jwk_extractable_value && extractable) |
504 return false; | 519 return Status::ErrorJwkExtractableInconsistent(); |
505 extractable = extractable && jwk_extractable_value; | 520 extractable = extractable && jwk_extractable_value; |
506 } | 521 } |
507 } | 522 } |
508 | 523 |
509 // JWK "alg" (optional) --> algorithm parameter | 524 // JWK "alg" (optional) --> algorithm parameter |
510 // Note: input algorithm is also optional, so we have six cases to handle. | 525 // Note: input algorithm is also optional, so we have six cases to handle. |
511 // 1. JWK alg present but unrecognized: error | 526 // 1. JWK alg present but unrecognized: error |
512 // 2. JWK alg valid AND input algorithm isNull: use JWK value | 527 // 2. JWK alg valid AND input algorithm isNull: use JWK value |
513 // 3. JWK alg valid AND input algorithm specified, but JWK value | 528 // 3. JWK alg valid AND input algorithm specified, but JWK value |
514 // inconsistent with input: error | 529 // inconsistent with input: error |
515 // 4. JWK alg valid AND input algorithm specified, both consistent: use | 530 // 4. JWK alg valid AND input algorithm specified, both consistent: use |
516 // input value (because it has potentially more details) | 531 // input value (because it has potentially more details) |
517 // 5. JWK alg missing AND input algorithm isNull: error | 532 // 5. JWK alg missing AND input algorithm isNull: error |
518 // 6. JWK alg missing AND input algorithm specified: use input value | 533 // 6. JWK alg missing AND input algorithm specified: use input value |
519 blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull(); | 534 blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull(); |
520 std::string jwk_alg_value; | 535 std::string jwk_alg_value; |
521 if (dict_value->GetString("alg", &jwk_alg_value)) { | 536 if (dict_value->GetString("alg", &jwk_alg_value)) { |
522 // JWK alg present | 537 // JWK alg present |
523 | 538 |
524 // TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can | 539 // TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can |
525 // only be from the RSA family. | 540 // only be from the RSA family. |
526 | 541 |
527 const blink::WebCryptoAlgorithm jwk_algorithm = | 542 const blink::WebCryptoAlgorithm jwk_algorithm = |
528 jwk_alg_factory.Get().CreateAlgorithmFromName(jwk_alg_value); | 543 jwk_alg_factory.Get().CreateAlgorithmFromName(jwk_alg_value); |
529 if (jwk_algorithm.isNull()) { | 544 if (jwk_algorithm.isNull()) { |
530 // JWK alg unrecognized | 545 // JWK alg unrecognized |
531 return false; // case 1 | 546 return Status::ErrorJwkUnrecognizedAlgorithm(); // case 1 |
532 } | 547 } |
533 // JWK alg valid | 548 // JWK alg valid |
534 if (algorithm_or_null.isNull()) { | 549 if (algorithm_or_null.isNull()) { |
535 // input algorithm not specified | 550 // input algorithm not specified |
536 algorithm = jwk_algorithm; // case 2 | 551 algorithm = jwk_algorithm; // case 2 |
537 } else { | 552 } else { |
538 // input algorithm specified | 553 // input algorithm specified |
539 if (!WebCryptoAlgorithmsConsistent(jwk_algorithm, algorithm_or_null)) | 554 if (!WebCryptoAlgorithmsConsistent(jwk_algorithm, algorithm_or_null)) |
540 return false; // case 3 | 555 return Status::ErrorJwkAlgorithmInconsistent(); // case 3 |
541 algorithm = algorithm_or_null; // case 4 | 556 algorithm = algorithm_or_null; // case 4 |
542 } | 557 } |
543 } else { | 558 } else { |
544 // JWK alg missing | 559 // JWK alg missing |
545 if (algorithm_or_null.isNull()) | 560 if (algorithm_or_null.isNull()) |
546 return false; // case 5 | 561 return Status::ErrorJwkAlgorithmMissing(); // case 5 |
547 algorithm = algorithm_or_null; // case 6 | 562 algorithm = algorithm_or_null; // case 6 |
548 } | 563 } |
549 DCHECK(!algorithm.isNull()); | 564 DCHECK(!algorithm.isNull()); |
550 | 565 |
551 // JWK "use" (optional) --> usage_mask parameter | 566 // JWK "use" (optional) --> usage_mask parameter |
552 std::string jwk_use_value; | 567 std::string jwk_use_value; |
553 if (dict_value->GetString("use", &jwk_use_value)) { | 568 if (dict_value->GetString("use", &jwk_use_value)) { |
554 blink::WebCryptoKeyUsageMask jwk_usage_mask = 0; | 569 blink::WebCryptoKeyUsageMask jwk_usage_mask = 0; |
555 if (jwk_use_value == "enc") { | 570 if (jwk_use_value == "enc") { |
556 jwk_usage_mask = | 571 jwk_usage_mask = |
557 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt; | 572 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt; |
558 } else if (jwk_use_value == "sig") { | 573 } else if (jwk_use_value == "sig") { |
559 jwk_usage_mask = | 574 jwk_usage_mask = |
560 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; | 575 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; |
561 } else if (jwk_use_value == "wrap") { | 576 } else if (jwk_use_value == "wrap") { |
562 jwk_usage_mask = | 577 jwk_usage_mask = |
563 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey; | 578 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey; |
564 } else { | 579 } else { |
565 return false; | 580 return Status::ErrorJwkUnrecognizedUsage(); |
566 } | 581 } |
567 if ((jwk_usage_mask & usage_mask) != usage_mask) { | 582 if ((jwk_usage_mask & usage_mask) != usage_mask) { |
568 // A usage_mask must be a subset of jwk_usage_mask. | 583 // A usage_mask must be a subset of jwk_usage_mask. |
569 return false; | 584 return Status::ErrorJwkUsageInconsistent(); |
570 } | 585 } |
571 } | 586 } |
572 | 587 |
573 // JWK keying material --> ImportKeyInternal() | 588 // JWK keying material --> ImportKeyInternal() |
574 if (jwk_kty_value == "oct") { | 589 if (jwk_kty_value == "oct") { |
575 | 590 |
576 std::string jwk_k_value; | 591 std::string jwk_k_value; |
577 if (!GetDecodedUrl64ValueByKey(*dict_value, "k", &jwk_k_value)) | 592 if (!GetDecodedUrl64ValueByKey(*dict_value, "k", &jwk_k_value)) |
578 return false; | 593 return Status::ErrorJwkDecodeK(); |
579 | 594 |
580 // TODO(padolph): Some JWK alg ID's embed information about the key length | 595 // TODO(padolph): Some JWK alg ID's embed information about the key length |
581 // in the alg ID string. For example "A128" implies the JWK carries 128 bits | 596 // in the alg ID string. For example "A128" implies the JWK carries 128 bits |
582 // of key material, and "HS512" implies the JWK carries _at least_ 512 bits | 597 // of key material, and "HS512" implies the JWK carries _at least_ 512 bits |
583 // of key material. For such keys validate the actual key length against the | 598 // of key material. For such keys validate the actual key length against the |
584 // value in the ID. | 599 // value in the ID. |
585 | 600 |
586 return ImportKeyInternal(blink::WebCryptoKeyFormatRaw, | 601 return ImportKeyInternal(blink::WebCryptoKeyFormatRaw, |
587 reinterpret_cast<const uint8*>(jwk_k_value.data()), | 602 reinterpret_cast<const uint8*>(jwk_k_value.data()), |
588 jwk_k_value.size(), | 603 jwk_k_value.size(), |
589 algorithm, | 604 algorithm, |
590 extractable, | 605 extractable, |
591 usage_mask, | 606 usage_mask, |
592 key); | 607 key); |
593 } else if (jwk_kty_value == "RSA") { | 608 } else if (jwk_kty_value == "RSA") { |
594 | 609 |
595 // 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 |
596 // 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" |
597 // (private exponent) entry. | 612 // (private exponent) entry. |
598 // 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, |
599 // section 6.3. | 614 // section 6.3. |
600 | 615 |
601 // RSA private key import is not currently supported, so fail here if a "d" | 616 // RSA private key import is not currently supported, so fail here if a "d" |
602 // entry is found. | 617 // entry is found. |
603 // TODO(padolph): Support RSA private key import. | 618 // TODO(padolph): Support RSA private key import. |
604 if (dict_value->HasKey("d")) | 619 if (dict_value->HasKey("d")) |
605 return false; | 620 return Status::ErrorJwkRsaPrivateKeyUnsupported(); |
606 | 621 |
607 std::string jwk_n_value; | 622 std::string jwk_n_value; |
608 if (!GetDecodedUrl64ValueByKey(*dict_value, "n", &jwk_n_value)) | 623 if (!GetDecodedUrl64ValueByKey(*dict_value, "n", &jwk_n_value)) |
609 return false; | 624 return Status::ErrorJwkDecodeN(); |
610 std::string jwk_e_value; | 625 std::string jwk_e_value; |
611 if (!GetDecodedUrl64ValueByKey(*dict_value, "e", &jwk_e_value)) | 626 if (!GetDecodedUrl64ValueByKey(*dict_value, "e", &jwk_e_value)) |
612 return false; | 627 return Status::ErrorJwkDecodeE(); |
613 | 628 |
614 return ImportRsaPublicKeyInternal( | 629 return ImportRsaPublicKeyInternal( |
615 reinterpret_cast<const uint8*>(jwk_n_value.data()), | 630 reinterpret_cast<const uint8*>(jwk_n_value.data()), |
616 jwk_n_value.size(), | 631 jwk_n_value.size(), |
617 reinterpret_cast<const uint8*>(jwk_e_value.data()), | 632 reinterpret_cast<const uint8*>(jwk_e_value.data()), |
618 jwk_e_value.size(), | 633 jwk_e_value.size(), |
619 algorithm, | 634 algorithm, |
620 extractable, | 635 extractable, |
621 usage_mask, | 636 usage_mask, |
622 key); | 637 key); |
623 | 638 |
624 } else { | 639 } else { |
625 return false; | 640 return Status::ErrorJwkUnrecognizedKty(); |
626 } | 641 } |
627 | 642 |
628 return true; | 643 return Status::Success(); |
629 } | 644 } |
630 | 645 |
631 } // namespace content | 646 } // namespace content |
OLD | NEW |