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