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