Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: content/renderer/webcrypto/webcrypto_impl_nss.cc

Issue 145083006: [webcrypto] Add error messages for failed operations. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix compiler warning on windows Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 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 <cryptohi.h> 7 #include <cryptohi.h>
8 #include <pk11pub.h> 8 #include <pk11pub.h>
9 #include <sechash.h> 9 #include <sechash.h>
10 10
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 105
106 PK11_EncryptDecryptFunction pk11_encrypt_func_; 106 PK11_EncryptDecryptFunction pk11_encrypt_func_;
107 PK11_EncryptDecryptFunction pk11_decrypt_func_; 107 PK11_EncryptDecryptFunction pk11_decrypt_func_;
108 }; 108 };
109 109
110 base::LazyInstance<AesGcmSupport>::Leaky g_aes_gcm_support = 110 base::LazyInstance<AesGcmSupport>::Leaky g_aes_gcm_support =
111 LAZY_INSTANCE_INITIALIZER; 111 LAZY_INSTANCE_INITIALIZER;
112 112
113 namespace content { 113 namespace content {
114 114
115 using webcrypto::Status;
116
115 namespace { 117 namespace {
116 118
117 class SymKeyHandle : public blink::WebCryptoKeyHandle { 119 class SymKeyHandle : public blink::WebCryptoKeyHandle {
118 public: 120 public:
119 explicit SymKeyHandle(crypto::ScopedPK11SymKey key) : key_(key.Pass()) {} 121 explicit SymKeyHandle(crypto::ScopedPK11SymKey key) : key_(key.Pass()) {}
120 122
121 PK11SymKey* key() { return key_.get(); } 123 PK11SymKey* key() { return key_.get(); }
122 124
123 private: 125 private:
124 crypto::ScopedPK11SymKey key_; 126 crypto::ScopedPK11SymKey key_;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 case blink::WebCryptoAlgorithmIdSha384: 185 case blink::WebCryptoAlgorithmIdSha384:
184 return CKM_SHA384_HMAC; 186 return CKM_SHA384_HMAC;
185 case blink::WebCryptoAlgorithmIdSha512: 187 case blink::WebCryptoAlgorithmIdSha512:
186 return CKM_SHA512_HMAC; 188 return CKM_SHA512_HMAC;
187 default: 189 default:
188 // Not a supported algorithm. 190 // Not a supported algorithm.
189 return CKM_INVALID_MECHANISM; 191 return CKM_INVALID_MECHANISM;
190 } 192 }
191 } 193 }
192 194
193 bool AesCbcEncryptDecrypt( 195 Status AesCbcEncryptDecrypt(
194 CK_ATTRIBUTE_TYPE operation, 196 CK_ATTRIBUTE_TYPE operation,
195 const blink::WebCryptoAlgorithm& algorithm, 197 const blink::WebCryptoAlgorithm& algorithm,
196 const blink::WebCryptoKey& key, 198 const blink::WebCryptoKey& key,
197 const unsigned char* data, 199 const unsigned char* data,
198 unsigned data_size, 200 unsigned data_size,
199 blink::WebArrayBuffer* buffer) { 201 blink::WebArrayBuffer* buffer) {
200 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesCbc, algorithm.id()); 202 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesCbc, algorithm.id());
201 DCHECK_EQ(algorithm.id(), key.algorithm().id()); 203 DCHECK_EQ(algorithm.id(), key.algorithm().id());
202 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); 204 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
203 DCHECK(operation == CKA_ENCRYPT || operation == CKA_DECRYPT); 205 DCHECK(operation == CKA_ENCRYPT || operation == CKA_DECRYPT);
204 206
205 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); 207 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle());
206 208
207 const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams(); 209 const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams();
208 if (params->iv().size() != AES_BLOCK_SIZE) 210 if (params->iv().size() != AES_BLOCK_SIZE)
209 return false; 211 return Status::ErrorIncorrectSizedAesCbcIv();
Ryan Sleevi 2014/01/28 21:11:58 nit: IncorrectlySized or IncorrectSize , but Incor
eroman 2014/01/28 22:59:08 Done.
210 212
211 SECItem iv_item; 213 SECItem iv_item;
212 iv_item.type = siBuffer; 214 iv_item.type = siBuffer;
213 iv_item.data = const_cast<unsigned char*>(params->iv().data()); 215 iv_item.data = const_cast<unsigned char*>(params->iv().data());
214 iv_item.len = params->iv().size(); 216 iv_item.len = params->iv().size();
215 217
216 crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item)); 218 crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item));
217 if (!param) 219 if (!param)
218 return false; 220 return Status::Error();
219 221
220 crypto::ScopedPK11Context context(PK11_CreateContextBySymKey( 222 crypto::ScopedPK11Context context(PK11_CreateContextBySymKey(
221 CKM_AES_CBC_PAD, operation, sym_key->key(), param.get())); 223 CKM_AES_CBC_PAD, operation, sym_key->key(), param.get()));
222 224
223 if (!context.get()) 225 if (!context.get())
224 return false; 226 return Status::Error();
225 227
226 // Oddly PK11_CipherOp takes input and output lengths as "int" rather than 228 // Oddly PK11_CipherOp takes input and output lengths as "int" rather than
227 // "unsigned". Do some checks now to avoid integer overflowing. 229 // "unsigned". Do some checks now to avoid integer overflowing.
228 if (data_size >= INT_MAX - AES_BLOCK_SIZE) { 230 if (data_size >= INT_MAX - AES_BLOCK_SIZE) {
229 // TODO(eroman): Handle this by chunking the input fed into NSS. Right now 231 // TODO(eroman): Handle this by chunking the input fed into NSS. Right now
230 // it doesn't make much difference since the one-shot API would end up 232 // it doesn't make much difference since the one-shot API would end up
231 // blowing out the memory and crashing anyway. However a newer version of 233 // blowing out the memory and crashing anyway.
232 // the spec allows for a sequence<CryptoData> so this will be relevant. 234 return Status::ErrorDataTooBig();
233 return false;
234 } 235 }
235 236
236 // PK11_CipherOp does an invalid memory access when given empty decryption 237 // PK11_CipherOp does an invalid memory access when given empty decryption
237 // input, or input which is not a multiple of the block size. See also 238 // input, or input which is not a multiple of the block size. See also
238 // https://bugzilla.mozilla.com/show_bug.cgi?id=921687. 239 // https://bugzilla.mozilla.com/show_bug.cgi?id=921687.
239 if (operation == CKA_DECRYPT && 240 if (operation == CKA_DECRYPT &&
240 (data_size == 0 || (data_size % AES_BLOCK_SIZE != 0))) { 241 (data_size == 0 || (data_size % AES_BLOCK_SIZE != 0))) {
241 return false; 242 return Status::Error();
242 } 243 }
243 244
244 // TODO(eroman): Refine the output buffer size. It can be computed exactly for 245 // TODO(eroman): Refine the output buffer size. It can be computed exactly for
245 // encryption, and can be smaller for decryption. 246 // encryption, and can be smaller for decryption.
246 unsigned output_max_len = data_size + AES_BLOCK_SIZE; 247 unsigned output_max_len = data_size + AES_BLOCK_SIZE;
247 CHECK_GT(output_max_len, data_size); 248 CHECK_GT(output_max_len, data_size);
248 249
249 *buffer = blink::WebArrayBuffer::create(output_max_len, 1); 250 *buffer = blink::WebArrayBuffer::create(output_max_len, 1);
250 251
251 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); 252 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data());
252 253
253 int output_len; 254 int output_len;
254 if (SECSuccess != PK11_CipherOp(context.get(), 255 if (SECSuccess != PK11_CipherOp(context.get(),
255 buffer_data, 256 buffer_data,
256 &output_len, 257 &output_len,
257 buffer->byteLength(), 258 buffer->byteLength(),
258 data, 259 data,
259 data_size)) { 260 data_size)) {
260 return false; 261 return Status::Error();
261 } 262 }
262 263
263 unsigned int final_output_chunk_len; 264 unsigned int final_output_chunk_len;
264 if (SECSuccess != PK11_DigestFinal(context.get(), 265 if (SECSuccess != PK11_DigestFinal(context.get(),
265 buffer_data + output_len, 266 buffer_data + output_len,
266 &final_output_chunk_len, 267 &final_output_chunk_len,
267 output_max_len - output_len)) { 268 output_max_len - output_len)) {
268 return false; 269 return Status::Error();
269 } 270 }
270 271
271 webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len); 272 webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len);
272 return true; 273 return Status::Success();
273 } 274 }
274 275
275 // Helper to either encrypt or decrypt for AES-GCM. The result of encryption is 276 // Helper to either encrypt or decrypt for AES-GCM. The result of encryption is
276 // the concatenation of the ciphertext and the authentication tag. Similarly, 277 // the concatenation of the ciphertext and the authentication tag. Similarly,
277 // this is the expectation for the input to decryption. 278 // this is the expectation for the input to decryption.
278 bool AesGcmEncryptDecrypt( 279 Status AesGcmEncryptDecrypt(
279 bool encrypt, 280 bool encrypt,
280 const blink::WebCryptoAlgorithm& algorithm, 281 const blink::WebCryptoAlgorithm& algorithm,
281 const blink::WebCryptoKey& key, 282 const blink::WebCryptoKey& key,
282 const unsigned char* data, 283 const unsigned char* data,
283 unsigned data_size, 284 unsigned data_size,
284 blink::WebArrayBuffer* buffer) { 285 blink::WebArrayBuffer* buffer) {
285 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesGcm, algorithm.id()); 286 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesGcm, algorithm.id());
286 DCHECK_EQ(algorithm.id(), key.algorithm().id()); 287 DCHECK_EQ(algorithm.id(), key.algorithm().id());
287 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); 288 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
288 289
289 if (!g_aes_gcm_support.Get().IsSupported()) 290 if (!g_aes_gcm_support.Get().IsSupported())
290 return false; 291 return Status::ErrorUnsupported();
Ryan Sleevi 2014/01/28 21:11:58 Remind me that we should clarify the error handlin
eroman 2014/01/28 22:59:08 Do you mean in the spec or in the implementation?
291 292
292 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); 293 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle());
293 294
294 const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams(); 295 const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams();
295 if (!params) 296 if (!params)
296 return false; 297 return Status::ErrorUnexpected();
297 298
298 // TODO(eroman): The spec doesn't define the default value. Assume 128 for now 299 // TODO(eroman): The spec doesn't define the default value. Assume 128 for now
299 // since that is the maximum tag length: 300 // since that is the maximum tag length:
300 // http://www.w3.org/2012/webcrypto/track/issues/46 301 // http://www.w3.org/2012/webcrypto/track/issues/46
301 unsigned tag_length_bits = 128; 302 unsigned tag_length_bits = 128;
302 if (params->hasTagLengthBits()) { 303 if (params->hasTagLengthBits()) {
303 tag_length_bits = params->optionalTagLengthBits(); 304 tag_length_bits = params->optionalTagLengthBits();
304 } 305 }
305 306
306 if (tag_length_bits > 128) { 307 if (tag_length_bits > 128 || (tag_length_bits % 8 != 0)) {
307 return false; 308 return Status::ErrorInvalidAesGcmTagLength();
308 } 309 }
309
310 if (tag_length_bits % 8 != 0)
311 return false;
312 unsigned tag_length_bytes = tag_length_bits / 8; 310 unsigned tag_length_bytes = tag_length_bits / 8;
313 311
314 CK_GCM_PARAMS gcm_params = {0}; 312 CK_GCM_PARAMS gcm_params = {0};
315 gcm_params.pIv = 313 gcm_params.pIv =
316 const_cast<unsigned char*>(algorithm.aesGcmParams()->iv().data()); 314 const_cast<unsigned char*>(algorithm.aesGcmParams()->iv().data());
317 gcm_params.ulIvLen = algorithm.aesGcmParams()->iv().size(); 315 gcm_params.ulIvLen = algorithm.aesGcmParams()->iv().size();
318 316
319 gcm_params.pAAD = 317 gcm_params.pAAD =
320 const_cast<unsigned char*>(params->optionalAdditionalData().data()); 318 const_cast<unsigned char*>(params->optionalAdditionalData().data());
321 gcm_params.ulAADLen = params->optionalAdditionalData().size(); 319 gcm_params.ulAADLen = params->optionalAdditionalData().size();
322 320
323 gcm_params.ulTagBits = tag_length_bits; 321 gcm_params.ulTagBits = tag_length_bits;
324 322
325 SECItem param; 323 SECItem param;
326 param.type = siBuffer; 324 param.type = siBuffer;
327 param.data = reinterpret_cast<unsigned char*>(&gcm_params); 325 param.data = reinterpret_cast<unsigned char*>(&gcm_params);
328 param.len = sizeof(gcm_params); 326 param.len = sizeof(gcm_params);
329 327
330 unsigned buffer_size = 0; 328 unsigned buffer_size = 0;
331 329
332 // Calculate the output buffer size. 330 // Calculate the output buffer size.
333 if (encrypt) { 331 if (encrypt) {
334 // TODO(eroman): This is ugly, abstract away the safe integer arithmetic. 332 // TODO(eroman): This is ugly, abstract away the safe integer arithmetic.
335 if (data_size > (UINT_MAX - tag_length_bytes)) 333 if (data_size > (UINT_MAX - tag_length_bytes))
336 return false; 334 return Status::ErrorDataTooBig();
337 buffer_size = data_size + tag_length_bytes; 335 buffer_size = data_size + tag_length_bytes;
338 } else { 336 } else {
339 // TODO(eroman): In theory the buffer allocated for the plain text should be 337 // TODO(eroman): In theory the buffer allocated for the plain text should be
340 // sized as |data_size - tag_length_bytes|. 338 // sized as |data_size - tag_length_bytes|.
341 // 339 //
342 // However NSS has a bug whereby it will fail if the output buffer size is 340 // However NSS has a bug whereby it will fail if the output buffer size is
343 // not at least as large as the ciphertext: 341 // not at least as large as the ciphertext:
344 // 342 //
345 // https://bugzilla.mozilla.org/show_bug.cgi?id=%20853674 343 // https://bugzilla.mozilla.org/show_bug.cgi?id=%20853674
346 // 344 //
347 // From the analysis of that bug it looks like it might be safe to pass a 345 // From the analysis of that bug it looks like it might be safe to pass a
348 // correctly sized buffer but lie about its size. Since resizing the 346 // correctly sized buffer but lie about its size. Since resizing the
349 // WebCryptoArrayBuffer is expensive that hack may be worth looking into. 347 // WebCryptoArrayBuffer is expensive that hack may be worth looking into.
350 buffer_size = data_size; 348 buffer_size = data_size;
351 } 349 }
352 350
353 *buffer = blink::WebArrayBuffer::create(buffer_size, 1); 351 *buffer = blink::WebArrayBuffer::create(buffer_size, 1);
354 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); 352 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data());
355 353
356 PK11_EncryptDecryptFunction func = 354 PK11_EncryptDecryptFunction func =
357 encrypt ? g_aes_gcm_support.Get().pk11_encrypt_func() : 355 encrypt ? g_aes_gcm_support.Get().pk11_encrypt_func() :
358 g_aes_gcm_support.Get().pk11_decrypt_func(); 356 g_aes_gcm_support.Get().pk11_decrypt_func();
359 357
360 unsigned int output_len = 0; 358 unsigned int output_len = 0;
361 SECStatus result = func(sym_key->key(), CKM_AES_GCM, &param, 359 SECStatus result = func(sym_key->key(), CKM_AES_GCM, &param,
362 buffer_data, &output_len, buffer->byteLength(), 360 buffer_data, &output_len, buffer->byteLength(),
363 data, data_size); 361 data, data_size);
364 362
365 if (result != SECSuccess) 363 if (result != SECSuccess)
366 return false; 364 return Status::Error();
367 365
368 // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug 366 // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug
369 // above). 367 // above).
370 webcrypto::ShrinkBuffer(buffer, output_len); 368 webcrypto::ShrinkBuffer(buffer, output_len);
371 369
372 return true; 370 return Status::Success();
373 } 371 }
374 372
375 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( 373 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism(
376 const blink::WebCryptoAlgorithm& algorithm) { 374 const blink::WebCryptoAlgorithm& algorithm) {
377 switch (algorithm.id()) { 375 switch (algorithm.id()) {
378 case blink::WebCryptoAlgorithmIdAesCbc: 376 case blink::WebCryptoAlgorithmIdAesCbc:
379 case blink::WebCryptoAlgorithmIdAesGcm: 377 case blink::WebCryptoAlgorithmIdAesGcm:
380 case blink::WebCryptoAlgorithmIdAesKw: 378 case blink::WebCryptoAlgorithmIdAesKw:
381 return CKM_AES_KEY_GEN; 379 return CKM_AES_KEY_GEN;
382 case blink::WebCryptoAlgorithmIdHmac: 380 case blink::WebCryptoAlgorithmIdHmac:
(...skipping 24 matching lines...) Expand all
407 } 405 }
408 return true; 406 return true;
409 } 407 }
410 408
411 bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm& algorithm) { 409 bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm& algorithm) {
412 return algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || 410 return algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 ||
413 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep || 411 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep ||
414 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; 412 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5;
415 } 413 }
416 414
417 bool ImportKeyInternalRaw( 415 Status ImportKeyInternalRaw(
418 const unsigned char* key_data, 416 const unsigned char* key_data,
419 unsigned key_data_size, 417 unsigned key_data_size,
420 const blink::WebCryptoAlgorithm& algorithm, 418 const blink::WebCryptoAlgorithm& algorithm,
421 bool extractable, 419 bool extractable,
422 blink::WebCryptoKeyUsageMask usage_mask, 420 blink::WebCryptoKeyUsageMask usage_mask,
423 blink::WebCryptoKey* key) { 421 blink::WebCryptoKey* key) {
424 422
425 DCHECK(!algorithm.isNull()); 423 DCHECK(!algorithm.isNull());
426 424
427 blink::WebCryptoKeyType type; 425 blink::WebCryptoKeyType type;
428 switch (algorithm.id()) { 426 switch (algorithm.id()) {
429 case blink::WebCryptoAlgorithmIdHmac: 427 case blink::WebCryptoAlgorithmIdHmac:
430 case blink::WebCryptoAlgorithmIdAesCbc: 428 case blink::WebCryptoAlgorithmIdAesCbc:
431 case blink::WebCryptoAlgorithmIdAesKw: 429 case blink::WebCryptoAlgorithmIdAesKw:
432 case blink::WebCryptoAlgorithmIdAesGcm: 430 case blink::WebCryptoAlgorithmIdAesGcm:
433 type = blink::WebCryptoKeyTypeSecret; 431 type = blink::WebCryptoKeyTypeSecret;
434 break; 432 break;
435 // TODO(bryaneyler): Support more key types. 433 // TODO(bryaneyler): Support more key types.
436 default: 434 default:
437 return false; 435 return Status::ErrorUnsupported();
438 } 436 }
439 437
440 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys. 438 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys.
441 // Currently only supporting symmetric. 439 // Currently only supporting symmetric.
442 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; 440 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
443 // Flags are verified at the Blink layer; here the flags are set to all 441 // Flags are verified at the Blink layer; here the flags are set to all
444 // possible operations for this key type. 442 // possible operations for this key type.
445 CK_FLAGS flags = 0; 443 CK_FLAGS flags = 0;
446 444
447 switch (algorithm.id()) { 445 switch (algorithm.id()) {
448 case blink::WebCryptoAlgorithmIdHmac: { 446 case blink::WebCryptoAlgorithmIdHmac: {
449 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); 447 const blink::WebCryptoHmacParams* params = algorithm.hmacParams();
450 if (!params) { 448 if (!params) {
451 return false; 449 return Status::ErrorUnexpected();
452 } 450 }
453 451
454 mechanism = WebCryptoHashToHMACMechanism(params->hash()); 452 mechanism = WebCryptoHashToHMACMechanism(params->hash());
455 if (mechanism == CKM_INVALID_MECHANISM) { 453 if (mechanism == CKM_INVALID_MECHANISM) {
456 return false; 454 return Status::ErrorUnsupported();
457 } 455 }
458 456
459 flags |= CKF_SIGN | CKF_VERIFY; 457 flags |= CKF_SIGN | CKF_VERIFY;
460 458
461 break; 459 break;
462 } 460 }
463 case blink::WebCryptoAlgorithmIdAesCbc: { 461 case blink::WebCryptoAlgorithmIdAesCbc: {
464 mechanism = CKM_AES_CBC; 462 mechanism = CKM_AES_CBC;
465 flags |= CKF_ENCRYPT | CKF_DECRYPT; 463 flags |= CKF_ENCRYPT | CKF_DECRYPT;
466 break; 464 break;
467 } 465 }
468 case blink::WebCryptoAlgorithmIdAesKw: { 466 case blink::WebCryptoAlgorithmIdAesKw: {
469 mechanism = CKM_NSS_AES_KEY_WRAP; 467 mechanism = CKM_NSS_AES_KEY_WRAP;
470 flags |= CKF_WRAP | CKF_WRAP; 468 flags |= CKF_WRAP | CKF_WRAP;
471 break; 469 break;
472 } 470 }
473 case blink::WebCryptoAlgorithmIdAesGcm: { 471 case blink::WebCryptoAlgorithmIdAesGcm: {
474 if (!g_aes_gcm_support.Get().IsSupported()) 472 if (!g_aes_gcm_support.Get().IsSupported())
475 return false; 473 return Status::ErrorUnsupported();
476 mechanism = CKM_AES_GCM; 474 mechanism = CKM_AES_GCM;
477 flags |= CKF_ENCRYPT | CKF_DECRYPT; 475 flags |= CKF_ENCRYPT | CKF_DECRYPT;
478 break; 476 break;
479 } 477 }
480 default: 478 default:
481 return false; 479 return Status::ErrorUnsupported();
482 } 480 }
483 481
484 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism); 482 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism);
485 DCHECK_NE(0ul, flags); 483 DCHECK_NE(0ul, flags);
486 484
487 SECItem key_item = { 485 SECItem key_item = {
488 siBuffer, 486 siBuffer,
489 const_cast<unsigned char*>(key_data), 487 const_cast<unsigned char*>(key_data),
490 key_data_size 488 key_data_size
491 }; 489 };
492 490
493 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); 491 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
494 crypto::ScopedPK11SymKey pk11_sym_key( 492 crypto::ScopedPK11SymKey pk11_sym_key(
495 PK11_ImportSymKeyWithFlags(slot.get(), 493 PK11_ImportSymKeyWithFlags(slot.get(),
496 mechanism, 494 mechanism,
497 PK11_OriginUnwrap, 495 PK11_OriginUnwrap,
498 CKA_FLAGS_ONLY, 496 CKA_FLAGS_ONLY,
499 &key_item, 497 &key_item,
500 flags, 498 flags,
501 false, 499 false,
502 NULL)); 500 NULL));
503 if (!pk11_sym_key.get()) { 501 if (!pk11_sym_key.get()) {
504 return false; 502 return Status::Error();
505 } 503 }
506 504
507 *key = blink::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()), 505 *key = blink::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()),
508 type, extractable, algorithm, usage_mask); 506 type, extractable, algorithm, usage_mask);
509 return true; 507 return Status::Success();
510 } 508 }
511 509
512 bool ExportKeyInternalRaw( 510 Status ExportKeyInternalRaw(
513 const blink::WebCryptoKey& key, 511 const blink::WebCryptoKey& key,
514 blink::WebArrayBuffer* buffer) { 512 blink::WebArrayBuffer* buffer) {
515 513
516 DCHECK(key.handle()); 514 DCHECK(key.handle());
517 DCHECK(buffer); 515 DCHECK(buffer);
518 516
519 if (key.type() != blink::WebCryptoKeyTypeSecret || !key.extractable()) 517 if (!key.extractable())
520 return false; 518 return Status::ErrorKeyNotExtractable();
519 if (key.type() != blink::WebCryptoKeyTypeSecret)
520 return Status::ErrorUnexpectedKeyType();
Ryan Sleevi 2014/01/28 21:11:58 s/Unexpected/Invalid?
eroman 2014/01/28 22:59:08 I left as is based on my own preference, but can c
521 521
522 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); 522 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle());
523 523
524 if (PK11_ExtractKeyValue(sym_key->key()) != SECSuccess) 524 if (PK11_ExtractKeyValue(sym_key->key()) != SECSuccess)
525 return false; 525 return Status::Error();
526 526
527 const SECItem* key_data = PK11_GetKeyData(sym_key->key()); 527 const SECItem* key_data = PK11_GetKeyData(sym_key->key());
528 if (!key_data) 528 if (!key_data)
529 return false; 529 return Status::Error();
530 530
531 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len); 531 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len);
532 532
533 return true; 533 return Status::Success();
534 } 534 }
535 535
536 typedef scoped_ptr<CERTSubjectPublicKeyInfo, 536 typedef scoped_ptr<CERTSubjectPublicKeyInfo,
537 crypto::NSSDestroyer<CERTSubjectPublicKeyInfo, 537 crypto::NSSDestroyer<CERTSubjectPublicKeyInfo,
538 SECKEY_DestroySubjectPublicKeyInfo> > 538 SECKEY_DestroySubjectPublicKeyInfo> >
539 ScopedCERTSubjectPublicKeyInfo; 539 ScopedCERTSubjectPublicKeyInfo;
540 540
541 // Validates an NSS KeyType against a WebCrypto algorithm. Some NSS KeyTypes 541 // Validates an NSS KeyType against a WebCrypto algorithm. Some NSS KeyTypes
542 // contain enough information to fabricate a Web Crypto algorithm, which is 542 // contain enough information to fabricate a Web Crypto algorithm, which is
543 // returned if the input algorithm isNull(). This function indicates failure by 543 // returned if the input algorithm isNull(). This function indicates failure by
(...skipping 17 matching lines...) Expand all
561 case rsaPssKey: 561 case rsaPssKey:
562 case rsaOaepKey: 562 case rsaOaepKey:
563 // TODO(padolph): Handle other key types. 563 // TODO(padolph): Handle other key types.
564 break; 564 break;
565 default: 565 default:
566 break; 566 break;
567 } 567 }
568 return blink::WebCryptoAlgorithm::createNull(); 568 return blink::WebCryptoAlgorithm::createNull();
569 } 569 }
570 570
571 bool ImportKeyInternalSpki( 571 Status ImportKeyInternalSpki(
572 const unsigned char* key_data, 572 const unsigned char* key_data,
573 unsigned key_data_size, 573 unsigned key_data_size,
574 const blink::WebCryptoAlgorithm& algorithm_or_null, 574 const blink::WebCryptoAlgorithm& algorithm_or_null,
575 bool extractable, 575 bool extractable,
576 blink::WebCryptoKeyUsageMask usage_mask, 576 blink::WebCryptoKeyUsageMask usage_mask,
577 blink::WebCryptoKey* key) { 577 blink::WebCryptoKey* key) {
578 578
579 DCHECK(key); 579 DCHECK(key);
580 580
581 if (!key_data_size) 581 if (!key_data_size)
582 return false; 582 return Status::ErrorImportEmptyKeyData();
583 DCHECK(key_data); 583 DCHECK(key_data);
584 584
585 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject 585 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject
586 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo. 586 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo.
587 SECItem spki_item = {siBuffer, const_cast<uint8*>(key_data), key_data_size}; 587 SECItem spki_item = {siBuffer, const_cast<uint8*>(key_data), key_data_size};
588 const ScopedCERTSubjectPublicKeyInfo spki( 588 const ScopedCERTSubjectPublicKeyInfo spki(
589 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); 589 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
590 if (!spki) 590 if (!spki)
591 return false; 591 return Status::Error();
592 592
593 crypto::ScopedSECKEYPublicKey sec_public_key( 593 crypto::ScopedSECKEYPublicKey sec_public_key(
594 SECKEY_ExtractPublicKey(spki.get())); 594 SECKEY_ExtractPublicKey(spki.get()));
595 if (!sec_public_key) 595 if (!sec_public_key)
596 return false; 596 return Status::Error();
597 597
598 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get()); 598 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get());
599 blink::WebCryptoAlgorithm algorithm = 599 blink::WebCryptoAlgorithm algorithm =
600 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null); 600 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null);
601 if (algorithm.isNull()) 601 if (algorithm.isNull())
602 return false; 602 return Status::Error();
603 603
604 *key = blink::WebCryptoKey::create( 604 *key = blink::WebCryptoKey::create(
605 new PublicKeyHandle(sec_public_key.Pass()), 605 new PublicKeyHandle(sec_public_key.Pass()),
606 blink::WebCryptoKeyTypePublic, 606 blink::WebCryptoKeyTypePublic,
607 extractable, 607 extractable,
608 algorithm, 608 algorithm,
609 usage_mask); 609 usage_mask);
610 610
611 return true; 611 return Status::Success();
612 } 612 }
613 613
614 bool ExportKeyInternalSpki( 614 Status ExportKeyInternalSpki(
615 const blink::WebCryptoKey& key, 615 const blink::WebCryptoKey& key,
616 blink::WebArrayBuffer* buffer) { 616 blink::WebArrayBuffer* buffer) {
617 617
618 DCHECK(key.handle()); 618 DCHECK(key.handle());
619 DCHECK(buffer); 619 DCHECK(buffer);
620 620
621 if (key.type() != blink::WebCryptoKeyTypePublic || !key.extractable()) 621 if (!key.extractable())
622 return false; 622 return Status::ErrorKeyNotExtractable();
623 if (key.type() != blink::WebCryptoKeyTypePublic)
624 return Status::ErrorUnexpectedKeyType();
623 625
624 PublicKeyHandle* const pub_key = 626 PublicKeyHandle* const pub_key =
625 reinterpret_cast<PublicKeyHandle*>(key.handle()); 627 reinterpret_cast<PublicKeyHandle*>(key.handle());
626 628
627 const crypto::ScopedSECItem spki_der( 629 const crypto::ScopedSECItem spki_der(
628 SECKEY_EncodeDERSubjectPublicKeyInfo(pub_key->key())); 630 SECKEY_EncodeDERSubjectPublicKeyInfo(pub_key->key()));
629 if (!spki_der) 631 if (!spki_der)
630 return false; 632 return Status::Error();
631 633
632 DCHECK(spki_der->data); 634 DCHECK(spki_der->data);
633 DCHECK(spki_der->len); 635 DCHECK(spki_der->len);
634 636
635 *buffer = webcrypto::CreateArrayBuffer(spki_der->data, spki_der->len); 637 *buffer = webcrypto::CreateArrayBuffer(spki_der->data, spki_der->len);
636 638
637 return true; 639 return Status::Success();
638 } 640 }
639 641
640 bool ImportKeyInternalPkcs8( 642 Status ImportKeyInternalPkcs8(
641 const unsigned char* key_data, 643 const unsigned char* key_data,
642 unsigned key_data_size, 644 unsigned key_data_size,
643 const blink::WebCryptoAlgorithm& algorithm_or_null, 645 const blink::WebCryptoAlgorithm& algorithm_or_null,
644 bool extractable, 646 bool extractable,
645 blink::WebCryptoKeyUsageMask usage_mask, 647 blink::WebCryptoKeyUsageMask usage_mask,
646 blink::WebCryptoKey* key) { 648 blink::WebCryptoKey* key) {
647 649
648 DCHECK(key); 650 DCHECK(key);
649 651
650 if (!key_data_size) 652 if (!key_data_size)
651 return false; 653 return Status::ErrorImportEmptyKeyData();
652 DCHECK(key_data); 654 DCHECK(key_data);
653 655
654 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8 656 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8
655 // private key info object. 657 // private key info object.
656 SECItem pki_der = {siBuffer, const_cast<uint8*>(key_data), key_data_size}; 658 SECItem pki_der = {siBuffer, const_cast<uint8*>(key_data), key_data_size};
657 659
658 SECKEYPrivateKey* seckey_private_key = NULL; 660 SECKEYPrivateKey* seckey_private_key = NULL;
659 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); 661 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
660 if (PK11_ImportDERPrivateKeyInfoAndReturnKey( 662 if (PK11_ImportDERPrivateKeyInfoAndReturnKey(
661 slot.get(), 663 slot.get(),
662 &pki_der, 664 &pki_der,
663 NULL, // nickname 665 NULL, // nickname
664 NULL, // publicValue 666 NULL, // publicValue
665 false, // isPerm 667 false, // isPerm
666 false, // isPrivate 668 false, // isPrivate
667 KU_ALL, // usage 669 KU_ALL, // usage
668 &seckey_private_key, 670 &seckey_private_key,
669 NULL) != SECSuccess) { 671 NULL) != SECSuccess) {
670 return false; 672 return Status::Error();
671 } 673 }
672 DCHECK(seckey_private_key); 674 DCHECK(seckey_private_key);
673 crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key); 675 crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key);
674 676
675 const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get()); 677 const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get());
676 blink::WebCryptoAlgorithm algorithm = 678 blink::WebCryptoAlgorithm algorithm =
677 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null); 679 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null);
678 if (algorithm.isNull()) 680 if (algorithm.isNull())
679 return false; 681 return Status::Error();
680 682
681 *key = blink::WebCryptoKey::create( 683 *key = blink::WebCryptoKey::create(
682 new PrivateKeyHandle(private_key.Pass()), 684 new PrivateKeyHandle(private_key.Pass()),
683 blink::WebCryptoKeyTypePrivate, 685 blink::WebCryptoKeyTypePrivate,
684 extractable, 686 extractable,
685 algorithm, 687 algorithm,
686 usage_mask); 688 usage_mask);
687 689
688 return true; 690 return Status::Success();
689 } 691 }
690 692
691 } // namespace 693 } // namespace
692 694
693 void WebCryptoImpl::Init() { 695 void WebCryptoImpl::Init() {
694 crypto::EnsureNSSInit(); 696 crypto::EnsureNSSInit();
695 } 697 }
696 698
697 bool WebCryptoImpl::EncryptInternal( 699 Status WebCryptoImpl::EncryptInternal(
698 const blink::WebCryptoAlgorithm& algorithm, 700 const blink::WebCryptoAlgorithm& algorithm,
699 const blink::WebCryptoKey& key, 701 const blink::WebCryptoKey& key,
700 const unsigned char* data, 702 const unsigned char* data,
701 unsigned data_size, 703 unsigned data_size,
702 blink::WebArrayBuffer* buffer) { 704 blink::WebArrayBuffer* buffer) {
703 705
704 DCHECK_EQ(algorithm.id(), key.algorithm().id()); 706 DCHECK_EQ(algorithm.id(), key.algorithm().id());
705 DCHECK(key.handle()); 707 DCHECK(key.handle());
706 DCHECK(buffer); 708 DCHECK(buffer);
707 709
708 // TODO(eroman): Use a switch() statement. 710 // TODO(eroman): Use a switch() statement.
709 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { 711 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) {
710 return AesCbcEncryptDecrypt( 712 return AesCbcEncryptDecrypt(
711 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); 713 CKA_ENCRYPT, algorithm, key, data, data_size, buffer);
712 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesGcm) { 714 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesGcm) {
713 return AesGcmEncryptDecrypt( 715 return AesGcmEncryptDecrypt(
714 true, algorithm, key, data, data_size, buffer); 716 true, algorithm, key, data, data_size, buffer);
715 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { 717 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) {
716 718
717 // RSAES encryption does not support empty input 719 // RSAES encryption does not support empty input
718 if (!data_size) 720 if (!data_size)
719 return false; 721 return Status::Error();
720 DCHECK(data); 722 DCHECK(data);
721 723
722 if (key.type() != blink::WebCryptoKeyTypePublic) 724 if (key.type() != blink::WebCryptoKeyTypePublic)
723 return false; 725 return Status::ErrorUnexpectedKeyType();
Ryan Sleevi 2014/01/28 21:11:58 Little weird to have this be Unexpected vs Unsuppo
eroman 2014/01/28 22:59:08 Not sure if I parsed the comment correctly. Do you
724 726
725 PublicKeyHandle* const public_key = 727 PublicKeyHandle* const public_key =
726 reinterpret_cast<PublicKeyHandle*>(key.handle()); 728 reinterpret_cast<PublicKeyHandle*>(key.handle());
727 729
728 const unsigned encrypted_length_bytes = 730 const unsigned encrypted_length_bytes =
729 SECKEY_PublicKeyStrength(public_key->key()); 731 SECKEY_PublicKeyStrength(public_key->key());
730 732
731 // RSAES can operate on messages up to a length of k - 11, where k is the 733 // RSAES can operate on messages up to a length of k - 11, where k is the
732 // octet length of the RSA modulus. 734 // octet length of the RSA modulus.
733 if (encrypted_length_bytes < 11 || encrypted_length_bytes - 11 < data_size) 735 if (encrypted_length_bytes < 11 || encrypted_length_bytes - 11 < data_size)
734 return false; 736 return Status::ErrorDataTooBig();
735 737
736 *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1); 738 *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1);
737 unsigned char* const buffer_data = 739 unsigned char* const buffer_data =
738 reinterpret_cast<unsigned char*>(buffer->data()); 740 reinterpret_cast<unsigned char*>(buffer->data());
739 741
740 if (PK11_PubEncryptPKCS1(public_key->key(), 742 if (PK11_PubEncryptPKCS1(public_key->key(),
741 buffer_data, 743 buffer_data,
742 const_cast<unsigned char*>(data), 744 const_cast<unsigned char*>(data),
743 data_size, 745 data_size,
744 NULL) != SECSuccess) { 746 NULL) != SECSuccess) {
745 return false; 747 return Status::Error();
746 } 748 }
747 return true; 749 return Status::Success();
748 } 750 }
749 751
750 return false; 752 return Status::ErrorUnsupported();
751 } 753 }
752 754
753 bool WebCryptoImpl::DecryptInternal( 755 Status WebCryptoImpl::DecryptInternal(
754 const blink::WebCryptoAlgorithm& algorithm, 756 const blink::WebCryptoAlgorithm& algorithm,
755 const blink::WebCryptoKey& key, 757 const blink::WebCryptoKey& key,
756 const unsigned char* data, 758 const unsigned char* data,
757 unsigned data_size, 759 unsigned data_size,
758 blink::WebArrayBuffer* buffer) { 760 blink::WebArrayBuffer* buffer) {
759 761
760 DCHECK_EQ(algorithm.id(), key.algorithm().id()); 762 DCHECK_EQ(algorithm.id(), key.algorithm().id());
761 DCHECK(key.handle()); 763 DCHECK(key.handle());
762 DCHECK(buffer); 764 DCHECK(buffer);
763 765
764 // TODO(eroman): Use a switch() statement. 766 // TODO(eroman): Use a switch() statement.
765 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { 767 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) {
766 return AesCbcEncryptDecrypt( 768 return AesCbcEncryptDecrypt(
767 CKA_DECRYPT, algorithm, key, data, data_size, buffer); 769 CKA_DECRYPT, algorithm, key, data, data_size, buffer);
768 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesGcm) { 770 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesGcm) {
769 return AesGcmEncryptDecrypt( 771 return AesGcmEncryptDecrypt(
770 false, algorithm, key, data, data_size, buffer); 772 false, algorithm, key, data, data_size, buffer);
771 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { 773 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) {
772 774
773 // RSAES decryption does not support empty input 775 // RSAES decryption does not support empty input
774 if (!data_size) 776 if (!data_size)
775 return false; 777 return Status::Error();
776 DCHECK(data); 778 DCHECK(data);
777 779
778 if (key.type() != blink::WebCryptoKeyTypePrivate) 780 if (key.type() != blink::WebCryptoKeyTypePrivate)
779 return false; 781 return Status::ErrorUnexpectedKeyType();
Ryan Sleevi 2014/01/28 21:11:58 Ditto
780 782
781 PrivateKeyHandle* const private_key = 783 PrivateKeyHandle* const private_key =
782 reinterpret_cast<PrivateKeyHandle*>(key.handle()); 784 reinterpret_cast<PrivateKeyHandle*>(key.handle());
783 785
784 const int modulus_length_bytes = 786 const int modulus_length_bytes =
785 PK11_GetPrivateModulusLen(private_key->key()); 787 PK11_GetPrivateModulusLen(private_key->key());
786 if (modulus_length_bytes <= 0) 788 if (modulus_length_bytes <= 0)
787 return false; 789 return Status::ErrorUnexpected();
788 const unsigned max_output_length_bytes = modulus_length_bytes; 790 const unsigned max_output_length_bytes = modulus_length_bytes;
789 791
790 *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1); 792 *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1);
791 unsigned char* const buffer_data = 793 unsigned char* const buffer_data =
792 reinterpret_cast<unsigned char*>(buffer->data()); 794 reinterpret_cast<unsigned char*>(buffer->data());
793 795
794 unsigned output_length_bytes = 0; 796 unsigned output_length_bytes = 0;
795 if (PK11_PrivDecryptPKCS1(private_key->key(), 797 if (PK11_PrivDecryptPKCS1(private_key->key(),
796 buffer_data, 798 buffer_data,
797 &output_length_bytes, 799 &output_length_bytes,
798 max_output_length_bytes, 800 max_output_length_bytes,
799 const_cast<unsigned char*>(data), 801 const_cast<unsigned char*>(data),
800 data_size) != SECSuccess) { 802 data_size) != SECSuccess) {
801 return false; 803 return Status::Error();
802 } 804 }
803 DCHECK_LE(output_length_bytes, max_output_length_bytes); 805 DCHECK_LE(output_length_bytes, max_output_length_bytes);
804 webcrypto::ShrinkBuffer(buffer, output_length_bytes); 806 webcrypto::ShrinkBuffer(buffer, output_length_bytes);
805 return true; 807 return Status::Success();
806 } 808 }
807 809
808 return false; 810 return Status::ErrorUnsupported();
809 } 811 }
810 812
811 bool WebCryptoImpl::DigestInternal( 813 Status WebCryptoImpl::DigestInternal(
812 const blink::WebCryptoAlgorithm& algorithm, 814 const blink::WebCryptoAlgorithm& algorithm,
813 const unsigned char* data, 815 const unsigned char* data,
814 unsigned data_size, 816 unsigned data_size,
815 blink::WebArrayBuffer* buffer) { 817 blink::WebArrayBuffer* buffer) {
816 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm); 818 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm);
817 if (hash_type == HASH_AlgNULL) { 819 if (hash_type == HASH_AlgNULL) {
818 return false; 820 return Status::ErrorUnsupported();
819 } 821 }
820 822
821 HASHContext* context = HASH_Create(hash_type); 823 HASHContext* context = HASH_Create(hash_type);
822 if (!context) { 824 if (!context) {
823 return false; 825 return Status::Error();
824 } 826 }
825 827
826 HASH_Begin(context); 828 HASH_Begin(context);
827 829
828 HASH_Update(context, data, data_size); 830 HASH_Update(context, data, data_size);
829 831
830 unsigned hash_result_length = HASH_ResultLenContext(context); 832 unsigned hash_result_length = HASH_ResultLenContext(context);
831 DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX)); 833 DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX));
832 834
833 *buffer = blink::WebArrayBuffer::create(hash_result_length, 1); 835 *buffer = blink::WebArrayBuffer::create(hash_result_length, 1);
834 836
835 unsigned char* digest = reinterpret_cast<unsigned char*>(buffer->data()); 837 unsigned char* digest = reinterpret_cast<unsigned char*>(buffer->data());
836 838
837 unsigned result_length = 0; 839 unsigned result_length = 0;
838 HASH_End(context, digest, &result_length, hash_result_length); 840 HASH_End(context, digest, &result_length, hash_result_length);
839 841
840 HASH_Destroy(context); 842 HASH_Destroy(context);
841 843
842 return result_length == hash_result_length; 844 if (result_length != hash_result_length) {
845 return Status::ErrorUnexpected();
846 }
847 return Status::Success();
843 } 848 }
844 849
845 bool WebCryptoImpl::GenerateKeyInternal( 850 Status WebCryptoImpl::GenerateKeyInternal(
846 const blink::WebCryptoAlgorithm& algorithm, 851 const blink::WebCryptoAlgorithm& algorithm,
847 bool extractable, 852 bool extractable,
848 blink::WebCryptoKeyUsageMask usage_mask, 853 blink::WebCryptoKeyUsageMask usage_mask,
849 blink::WebCryptoKey* key) { 854 blink::WebCryptoKey* key) {
850 855
851 CK_MECHANISM_TYPE mech = WebCryptoAlgorithmToGenMechanism(algorithm); 856 CK_MECHANISM_TYPE mech = WebCryptoAlgorithmToGenMechanism(algorithm);
852 unsigned int keylen_bytes = 0; 857 unsigned int keylen_bytes = 0;
853 blink::WebCryptoKeyType key_type = blink::WebCryptoKeyTypeSecret; 858 blink::WebCryptoKeyType key_type = blink::WebCryptoKeyTypeSecret;
854 859
855 if (mech == CKM_INVALID_MECHANISM) { 860 if (mech == CKM_INVALID_MECHANISM) {
856 return false; 861 return Status::ErrorUnsupported();
857 } 862 }
858 863
859 switch (algorithm.id()) { 864 switch (algorithm.id()) {
860 case blink::WebCryptoAlgorithmIdAesCbc: 865 case blink::WebCryptoAlgorithmIdAesCbc:
861 case blink::WebCryptoAlgorithmIdAesGcm: 866 case blink::WebCryptoAlgorithmIdAesGcm:
862 case blink::WebCryptoAlgorithmIdAesKw: { 867 case blink::WebCryptoAlgorithmIdAesKw: {
863 const blink::WebCryptoAesKeyGenParams* params = 868 const blink::WebCryptoAesKeyGenParams* params =
864 algorithm.aesKeyGenParams(); 869 algorithm.aesKeyGenParams();
865 DCHECK(params); 870 DCHECK(params);
866 // Ensure the key length is a multiple of 8 bits. Let NSS verify further 871 // Ensure the key length is a multiple of 8 bits. Let NSS verify further
867 // algorithm-specific length restrictions. 872 // algorithm-specific length restrictions.
868 if (params->lengthBits() % 8) 873 if (params->lengthBits() % 8)
869 return false; 874 return Status::ErrorGenerateKeyLength();
870 keylen_bytes = params->lengthBits() / 8; 875 keylen_bytes = params->lengthBits() / 8;
871 key_type = blink::WebCryptoKeyTypeSecret; 876 key_type = blink::WebCryptoKeyTypeSecret;
872 break; 877 break;
873 } 878 }
874 case blink::WebCryptoAlgorithmIdHmac: { 879 case blink::WebCryptoAlgorithmIdHmac: {
875 const blink::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams(); 880 const blink::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams();
876 DCHECK(params); 881 DCHECK(params);
877 if (params->hasLengthBytes()) { 882 if (params->hasLengthBytes()) {
878 keylen_bytes = params->optionalLengthBytes(); 883 keylen_bytes = params->optionalLengthBytes();
879 } else { 884 } else {
880 keylen_bytes = webcrypto::ShaBlockSizeBytes(params->hash().id()); 885 keylen_bytes = webcrypto::ShaBlockSizeBytes(params->hash().id());
881 } 886 }
882 887
883 key_type = blink::WebCryptoKeyTypeSecret; 888 key_type = blink::WebCryptoKeyTypeSecret;
884 break; 889 break;
885 } 890 }
886 891
887 default: { 892 default: {
888 return false; 893 return Status::ErrorUnsupported();
889 } 894 }
890 } 895 }
891 896
892 if (keylen_bytes == 0) { 897 if (keylen_bytes == 0) {
893 return false; 898 return Status::ErrorGenerateKeyLength();
894 } 899 }
895 900
896 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot()); 901 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
897 if (!slot) { 902 if (!slot) {
898 return false; 903 return Status::Error();
899 } 904 }
900 905
901 crypto::ScopedPK11SymKey pk11_key( 906 crypto::ScopedPK11SymKey pk11_key(
902 PK11_KeyGen(slot.get(), mech, NULL, keylen_bytes, NULL)); 907 PK11_KeyGen(slot.get(), mech, NULL, keylen_bytes, NULL));
903 908
904 if (!pk11_key) { 909 if (!pk11_key) {
905 return false; 910 return Status::Error();
906 } 911 }
907 912
908 *key = blink::WebCryptoKey::create( 913 *key = blink::WebCryptoKey::create(
909 new SymKeyHandle(pk11_key.Pass()), 914 new SymKeyHandle(pk11_key.Pass()),
910 key_type, extractable, algorithm, usage_mask); 915 key_type, extractable, algorithm, usage_mask);
911 return true; 916 return Status::Success();
912 } 917 }
913 918
914 bool WebCryptoImpl::GenerateKeyPairInternal( 919 Status WebCryptoImpl::GenerateKeyPairInternal(
915 const blink::WebCryptoAlgorithm& algorithm, 920 const blink::WebCryptoAlgorithm& algorithm,
916 bool extractable, 921 bool extractable,
917 blink::WebCryptoKeyUsageMask usage_mask, 922 blink::WebCryptoKeyUsageMask usage_mask,
918 blink::WebCryptoKey* public_key, 923 blink::WebCryptoKey* public_key,
919 blink::WebCryptoKey* private_key) { 924 blink::WebCryptoKey* private_key) {
920 925
921 // TODO(padolph): Handle other asymmetric algorithm key generation. 926 // TODO(padolph): Handle other asymmetric algorithm key generation.
922 switch (algorithm.id()) { 927 switch (algorithm.id()) {
923 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: 928 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
924 case blink::WebCryptoAlgorithmIdRsaOaep: 929 case blink::WebCryptoAlgorithmIdRsaOaep:
925 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: { 930 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: {
926 const blink::WebCryptoRsaKeyGenParams* const params = 931 const blink::WebCryptoRsaKeyGenParams* const params =
927 algorithm.rsaKeyGenParams(); 932 algorithm.rsaKeyGenParams();
928 DCHECK(params); 933 DCHECK(params);
929 934
930 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot()); 935 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
936 if (!slot)
937 return Status::Error();
938
931 unsigned long public_exponent; 939 unsigned long public_exponent;
932 if (!slot || !params->modulusLengthBits() || 940 if (!params->modulusLengthBits())
933 !BigIntegerToLong(params->publicExponent().data(), 941 return Status::ErrorGenerateRsaZeroModulus();
942
943 if (!BigIntegerToLong(params->publicExponent().data(),
934 params->publicExponent().size(), 944 params->publicExponent().size(),
935 &public_exponent) || 945 &public_exponent) || !public_exponent) {
936 !public_exponent) { 946 return Status::ErrorGenerateKeyPublicExponent();
937 return false;
938 } 947 }
939 948
940 PK11RSAGenParams rsa_gen_params; 949 PK11RSAGenParams rsa_gen_params;
941 rsa_gen_params.keySizeInBits = params->modulusLengthBits(); 950 rsa_gen_params.keySizeInBits = params->modulusLengthBits();
942 rsa_gen_params.pe = public_exponent; 951 rsa_gen_params.pe = public_exponent;
943 952
944 // Flags are verified at the Blink layer; here the flags are set to all 953 // Flags are verified at the Blink layer; here the flags are set to all
945 // possible operations for the given key type. 954 // possible operations for the given key type.
946 CK_FLAGS operation_flags; 955 CK_FLAGS operation_flags;
947 switch (algorithm.id()) { 956 switch (algorithm.id()) {
948 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: 957 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
949 case blink::WebCryptoAlgorithmIdRsaOaep: 958 case blink::WebCryptoAlgorithmIdRsaOaep:
950 operation_flags = CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP; 959 operation_flags = CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP;
951 break; 960 break;
952 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: 961 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
953 operation_flags = CKF_SIGN | CKF_VERIFY; 962 operation_flags = CKF_SIGN | CKF_VERIFY;
954 break; 963 break;
955 default: 964 default:
956 NOTREACHED(); 965 NOTREACHED();
957 return false; 966 return Status::ErrorUnexpected();
958 } 967 }
959 const CK_FLAGS operation_flags_mask = CKF_ENCRYPT | CKF_DECRYPT | 968 const CK_FLAGS operation_flags_mask = CKF_ENCRYPT | CKF_DECRYPT |
960 CKF_SIGN | CKF_VERIFY | CKF_WRAP | 969 CKF_SIGN | CKF_VERIFY | CKF_WRAP |
961 CKF_UNWRAP; 970 CKF_UNWRAP;
962 const PK11AttrFlags attribute_flags = 0; // Default all PK11_ATTR_ flags. 971 const PK11AttrFlags attribute_flags = 0; // Default all PK11_ATTR_ flags.
963 972
964 // Note: NSS does not generate an sec_public_key if the call below fails, 973 // Note: NSS does not generate an sec_public_key if the call below fails,
965 // so there is no danger of a leaked sec_public_key. 974 // so there is no danger of a leaked sec_public_key.
966 SECKEYPublicKey* sec_public_key; 975 SECKEYPublicKey* sec_public_key;
967 crypto::ScopedSECKEYPrivateKey scoped_sec_private_key( 976 crypto::ScopedSECKEYPrivateKey scoped_sec_private_key(
968 PK11_GenerateKeyPairWithOpFlags(slot.get(), 977 PK11_GenerateKeyPairWithOpFlags(slot.get(),
969 CKM_RSA_PKCS_KEY_PAIR_GEN, 978 CKM_RSA_PKCS_KEY_PAIR_GEN,
970 &rsa_gen_params, 979 &rsa_gen_params,
971 &sec_public_key, 980 &sec_public_key,
972 attribute_flags, 981 attribute_flags,
973 operation_flags, 982 operation_flags,
974 operation_flags_mask, 983 operation_flags_mask,
975 NULL)); 984 NULL));
976 if (!private_key) { 985 if (!private_key) {
977 return false; 986 return Status::Error();
978 } 987 }
979 988
980 *public_key = blink::WebCryptoKey::create( 989 *public_key = blink::WebCryptoKey::create(
981 new PublicKeyHandle(crypto::ScopedSECKEYPublicKey(sec_public_key)), 990 new PublicKeyHandle(crypto::ScopedSECKEYPublicKey(sec_public_key)),
982 blink::WebCryptoKeyTypePublic, 991 blink::WebCryptoKeyTypePublic,
983 true, 992 true,
984 algorithm, 993 algorithm,
985 usage_mask); 994 usage_mask);
986 *private_key = blink::WebCryptoKey::create( 995 *private_key = blink::WebCryptoKey::create(
987 new PrivateKeyHandle(scoped_sec_private_key.Pass()), 996 new PrivateKeyHandle(scoped_sec_private_key.Pass()),
988 blink::WebCryptoKeyTypePrivate, 997 blink::WebCryptoKeyTypePrivate,
989 extractable, 998 extractable,
990 algorithm, 999 algorithm,
991 usage_mask); 1000 usage_mask);
992 1001
993 return true; 1002 return Status::Success();
994 } 1003 }
995 default: 1004 default:
996 return false; 1005 return Status::ErrorUnsupported();
997 } 1006 }
998 } 1007 }
999 1008
1000 bool WebCryptoImpl::ImportKeyInternal( 1009 Status WebCryptoImpl::ImportKeyInternal(
1001 blink::WebCryptoKeyFormat format, 1010 blink::WebCryptoKeyFormat format,
1002 const unsigned char* key_data, 1011 const unsigned char* key_data,
1003 unsigned key_data_size, 1012 unsigned key_data_size,
1004 const blink::WebCryptoAlgorithm& algorithm_or_null, 1013 const blink::WebCryptoAlgorithm& algorithm_or_null,
1005 bool extractable, 1014 bool extractable,
1006 blink::WebCryptoKeyUsageMask usage_mask, 1015 blink::WebCryptoKeyUsageMask usage_mask,
1007 blink::WebCryptoKey* key) { 1016 blink::WebCryptoKey* key) {
1008 1017
1009 switch (format) { 1018 switch (format) {
1010 case blink::WebCryptoKeyFormatRaw: 1019 case blink::WebCryptoKeyFormatRaw:
1011 // A 'raw'-formatted key import requires an input algorithm. 1020 // A 'raw'-formatted key import requires an input algorithm.
1012 if (algorithm_or_null.isNull()) 1021 if (algorithm_or_null.isNull())
1013 return false; 1022 return Status::ErrorMissingAlgorithmImportRawKey();
1014 return ImportKeyInternalRaw(key_data, 1023 return ImportKeyInternalRaw(key_data,
1015 key_data_size, 1024 key_data_size,
1016 algorithm_or_null, 1025 algorithm_or_null,
1017 extractable, 1026 extractable,
1018 usage_mask, 1027 usage_mask,
1019 key); 1028 key);
1020 case blink::WebCryptoKeyFormatSpki: 1029 case blink::WebCryptoKeyFormatSpki:
1021 return ImportKeyInternalSpki(key_data, 1030 return ImportKeyInternalSpki(key_data,
1022 key_data_size, 1031 key_data_size,
1023 algorithm_or_null, 1032 algorithm_or_null,
1024 extractable, 1033 extractable,
1025 usage_mask, 1034 usage_mask,
1026 key); 1035 key);
1027 case blink::WebCryptoKeyFormatPkcs8: 1036 case blink::WebCryptoKeyFormatPkcs8:
1028 return ImportKeyInternalPkcs8(key_data, 1037 return ImportKeyInternalPkcs8(key_data,
1029 key_data_size, 1038 key_data_size,
1030 algorithm_or_null, 1039 algorithm_or_null,
1031 extractable, 1040 extractable,
1032 usage_mask, 1041 usage_mask,
1033 key); 1042 key);
1034 default: 1043 default:
1035 // NOTE: blink::WebCryptoKeyFormatJwk is handled one level above. 1044 // NOTE: blink::WebCryptoKeyFormatJwk is handled one level above.
1036 return false; 1045 return Status::ErrorUnsupported();
1037 } 1046 }
1038 } 1047 }
1039 1048
1040 bool WebCryptoImpl::ExportKeyInternal( 1049 Status WebCryptoImpl::ExportKeyInternal(
1041 blink::WebCryptoKeyFormat format, 1050 blink::WebCryptoKeyFormat format,
1042 const blink::WebCryptoKey& key, 1051 const blink::WebCryptoKey& key,
1043 blink::WebArrayBuffer* buffer) { 1052 blink::WebArrayBuffer* buffer) {
1044 switch (format) { 1053 switch (format) {
1045 case blink::WebCryptoKeyFormatRaw: 1054 case blink::WebCryptoKeyFormatRaw:
1046 return ExportKeyInternalRaw(key, buffer); 1055 return ExportKeyInternalRaw(key, buffer);
1047 case blink::WebCryptoKeyFormatSpki: 1056 case blink::WebCryptoKeyFormatSpki:
1048 return ExportKeyInternalSpki(key, buffer); 1057 return ExportKeyInternalSpki(key, buffer);
1049 case blink::WebCryptoKeyFormatPkcs8: 1058 case blink::WebCryptoKeyFormatPkcs8:
1050 // TODO(padolph): Implement pkcs8 export 1059 // TODO(padolph): Implement pkcs8 export
1051 return false; 1060 return Status::ErrorUnsupported();
1052 default: 1061 default:
1053 return false; 1062 return Status::ErrorUnsupported();
1054 } 1063 }
1055 } 1064 }
1056 1065
1057 bool WebCryptoImpl::SignInternal( 1066 Status WebCryptoImpl::SignInternal(
1058 const blink::WebCryptoAlgorithm& algorithm, 1067 const blink::WebCryptoAlgorithm& algorithm,
1059 const blink::WebCryptoKey& key, 1068 const blink::WebCryptoKey& key,
1060 const unsigned char* data, 1069 const unsigned char* data,
1061 unsigned data_size, 1070 unsigned data_size,
1062 blink::WebArrayBuffer* buffer) { 1071 blink::WebArrayBuffer* buffer) {
1063 1072
1064 // Note: It is not an error to sign empty data. 1073 // Note: It is not an error to sign empty data.
1065 1074
1066 DCHECK(buffer); 1075 DCHECK(buffer);
1067 DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign); 1076 DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign);
1068 1077
1069 blink::WebArrayBuffer result; 1078 blink::WebArrayBuffer result;
1070 1079
1071 switch (algorithm.id()) { 1080 switch (algorithm.id()) {
1072 case blink::WebCryptoAlgorithmIdHmac: { 1081 case blink::WebCryptoAlgorithmIdHmac: {
1073 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); 1082 const blink::WebCryptoHmacParams* params = algorithm.hmacParams();
1074 if (!params) { 1083 if (!params) {
1075 return false; 1084 return Status::ErrorUnexpected();
1076 } 1085 }
1077 1086
1078 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); 1087 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle());
1079 1088
1080 DCHECK_EQ(PK11_GetMechanism(sym_key->key()), 1089 DCHECK_EQ(PK11_GetMechanism(sym_key->key()),
1081 WebCryptoHashToHMACMechanism(params->hash())); 1090 WebCryptoHashToHMACMechanism(params->hash()));
1082 1091
1083 SECItem param_item = { siBuffer, NULL, 0 }; 1092 SECItem param_item = { siBuffer, NULL, 0 };
1084 SECItem data_item = { 1093 SECItem data_item = {
1085 siBuffer, 1094 siBuffer,
1086 const_cast<unsigned char*>(data), 1095 const_cast<unsigned char*>(data),
1087 data_size 1096 data_size
1088 }; 1097 };
1089 // First call is to figure out the length. 1098 // First call is to figure out the length.
1090 SECItem signature_item = { siBuffer, NULL, 0 }; 1099 SECItem signature_item = { siBuffer, NULL, 0 };
1091 1100
1092 if (PK11_SignWithSymKey(sym_key->key(), 1101 if (PK11_SignWithSymKey(sym_key->key(),
1093 PK11_GetMechanism(sym_key->key()), 1102 PK11_GetMechanism(sym_key->key()),
1094 &param_item, 1103 &param_item,
1095 &signature_item, 1104 &signature_item,
1096 &data_item) != SECSuccess) { 1105 &data_item) != SECSuccess) {
1097 NOTREACHED(); 1106 return Status::Error();
1098 return false;
1099 } 1107 }
1100 1108
1101 DCHECK_NE(0u, signature_item.len); 1109 DCHECK_NE(0u, signature_item.len);
1102 1110
1103 result = blink::WebArrayBuffer::create(signature_item.len, 1); 1111 result = blink::WebArrayBuffer::create(signature_item.len, 1);
1104 signature_item.data = reinterpret_cast<unsigned char*>(result.data()); 1112 signature_item.data = reinterpret_cast<unsigned char*>(result.data());
1105 1113
1106 if (PK11_SignWithSymKey(sym_key->key(), 1114 if (PK11_SignWithSymKey(sym_key->key(),
1107 PK11_GetMechanism(sym_key->key()), 1115 PK11_GetMechanism(sym_key->key()),
1108 &param_item, 1116 &param_item,
1109 &signature_item, 1117 &signature_item,
1110 &data_item) != SECSuccess) { 1118 &data_item) != SECSuccess) {
1111 NOTREACHED(); 1119 return Status::Error();
1112 return false;
1113 } 1120 }
1114 1121
1115 DCHECK_EQ(result.byteLength(), signature_item.len); 1122 DCHECK_EQ(result.byteLength(), signature_item.len);
1116 1123
1117 break; 1124 break;
1118 } 1125 }
1119 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: { 1126 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: {
1120 if (key.type() != blink::WebCryptoKeyTypePrivate || 1127 if (key.type() != blink::WebCryptoKeyTypePrivate)
1121 webcrypto::GetInnerHashAlgorithm(algorithm).isNull()) 1128 return Status::ErrorUnexpectedKeyType();
1122 return false; 1129
1130 if (webcrypto::GetInnerHashAlgorithm(algorithm).isNull())
1131 return Status::ErrorUnexpected();
1123 1132
1124 PrivateKeyHandle* const private_key = 1133 PrivateKeyHandle* const private_key =
1125 reinterpret_cast<PrivateKeyHandle*>(key.handle()); 1134 reinterpret_cast<PrivateKeyHandle*>(key.handle());
1126 DCHECK(private_key); 1135 DCHECK(private_key);
1127 DCHECK(private_key->key()); 1136 DCHECK(private_key->key());
1128 1137
1129 // Pick the NSS signing algorithm by combining RSA-SSA (RSA PKCS1) and the 1138 // Pick the NSS signing algorithm by combining RSA-SSA (RSA PKCS1) and the
1130 // inner hash of the input Web Crypto algorithm. 1139 // inner hash of the input Web Crypto algorithm.
1131 SECOidTag sign_alg_tag; 1140 SECOidTag sign_alg_tag;
1132 switch (webcrypto::GetInnerHashAlgorithm(algorithm).id()) { 1141 switch (webcrypto::GetInnerHashAlgorithm(algorithm).id()) {
1133 case blink::WebCryptoAlgorithmIdSha1: 1142 case blink::WebCryptoAlgorithmIdSha1:
1134 sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; 1143 sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
1135 break; 1144 break;
1136 case blink::WebCryptoAlgorithmIdSha224: 1145 case blink::WebCryptoAlgorithmIdSha224:
1137 sign_alg_tag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION; 1146 sign_alg_tag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION;
1138 break; 1147 break;
1139 case blink::WebCryptoAlgorithmIdSha256: 1148 case blink::WebCryptoAlgorithmIdSha256:
1140 sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; 1149 sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
1141 break; 1150 break;
1142 case blink::WebCryptoAlgorithmIdSha384: 1151 case blink::WebCryptoAlgorithmIdSha384:
1143 sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; 1152 sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
1144 break; 1153 break;
1145 case blink::WebCryptoAlgorithmIdSha512: 1154 case blink::WebCryptoAlgorithmIdSha512:
1146 sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; 1155 sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
1147 break; 1156 break;
1148 default: 1157 default:
1149 return false; 1158 return Status::ErrorUnsupported();
1150 } 1159 }
1151 1160
1152 crypto::ScopedSECItem signature_item(SECITEM_AllocItem(NULL, NULL, 0)); 1161 crypto::ScopedSECItem signature_item(SECITEM_AllocItem(NULL, NULL, 0));
1153 if (SEC_SignData(signature_item.get(), 1162 if (SEC_SignData(signature_item.get(),
1154 data, 1163 data,
1155 data_size, 1164 data_size,
1156 private_key->key(), 1165 private_key->key(),
1157 sign_alg_tag) != SECSuccess) { 1166 sign_alg_tag) != SECSuccess) {
1158 return false; 1167 return Status::Error();
1159 } 1168 }
1160 1169
1161 result = webcrypto::CreateArrayBuffer(signature_item->data, 1170 result = webcrypto::CreateArrayBuffer(signature_item->data,
1162 signature_item->len); 1171 signature_item->len);
1163 1172
1164 break; 1173 break;
1165 } 1174 }
1166 default: 1175 default:
1167 return false; 1176 return Status::ErrorUnsupported();
1168 } 1177 }
1169 1178
1170 *buffer = result; 1179 *buffer = result;
1171 return true; 1180 return Status::Success();
1172 } 1181 }
1173 1182
1174 bool WebCryptoImpl::VerifySignatureInternal( 1183 Status WebCryptoImpl::VerifySignatureInternal(
1175 const blink::WebCryptoAlgorithm& algorithm, 1184 const blink::WebCryptoAlgorithm& algorithm,
1176 const blink::WebCryptoKey& key, 1185 const blink::WebCryptoKey& key,
1177 const unsigned char* signature, 1186 const unsigned char* signature,
1178 unsigned signature_size, 1187 unsigned signature_size,
1179 const unsigned char* data, 1188 const unsigned char* data,
1180 unsigned data_size, 1189 unsigned data_size,
1181 bool* signature_match) { 1190 bool* signature_match) {
1182 1191
1183 if (!signature_size) 1192 if (!signature_size) {
1184 return false; 1193 // None of the algorithms generate valid zero-length signatures so this
1194 // will necessarily fail verification. Early return to protect
1195 // implementations from dealing with a NULL signature pointer.
1196 *signature_match = false;
1197 return Status::Success();
1198 }
1199
1185 DCHECK(signature); 1200 DCHECK(signature);
1186 1201
1187 switch (algorithm.id()) { 1202 switch (algorithm.id()) {
1188 case blink::WebCryptoAlgorithmIdHmac: { 1203 case blink::WebCryptoAlgorithmIdHmac: {
1189 blink::WebArrayBuffer result; 1204 blink::WebArrayBuffer result;
1190 if (!SignInternal(algorithm, key, data, data_size, &result)) { 1205 Status status = SignInternal(algorithm, key, data, data_size, &result);
1191 return false; 1206 if (status.IsError()) {
1207 return status;
1192 } 1208 }
1193 1209
1194 // Handling of truncated signatures is underspecified in the WebCrypto 1210 // Handling of truncated signatures is underspecified in the WebCrypto
1195 // spec, so here we fail verification if a truncated signature is being 1211 // spec, so here we fail verification if a truncated signature is being
1196 // verified. 1212 // verified.
1197 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 1213 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097
1198 *signature_match = 1214 *signature_match =
1199 result.byteLength() == signature_size && 1215 result.byteLength() == signature_size &&
1200 crypto::SecureMemEqual(result.data(), signature, signature_size); 1216 crypto::SecureMemEqual(result.data(), signature, signature_size);
1201 1217
1202 break; 1218 break;
1203 } 1219 }
1204 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: { 1220 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: {
1205 if (key.type() != blink::WebCryptoKeyTypePublic) 1221 if (key.type() != blink::WebCryptoKeyTypePublic)
1206 return false; 1222 return Status::ErrorUnexpectedKeyType();
1207 1223
1208 PublicKeyHandle* const public_key = 1224 PublicKeyHandle* const public_key =
1209 reinterpret_cast<PublicKeyHandle*>(key.handle()); 1225 reinterpret_cast<PublicKeyHandle*>(key.handle());
1210 DCHECK(public_key); 1226 DCHECK(public_key);
1211 DCHECK(public_key->key()); 1227 DCHECK(public_key->key());
1212 1228
1213 const SECItem signature_item = { 1229 const SECItem signature_item = {
1214 siBuffer, 1230 siBuffer,
1215 const_cast<unsigned char*>(signature), 1231 const_cast<unsigned char*>(signature),
1216 signature_size 1232 signature_size
(...skipping 10 matching lines...) Expand all
1227 case blink::WebCryptoAlgorithmIdSha256: 1243 case blink::WebCryptoAlgorithmIdSha256:
1228 hash_alg_tag = SEC_OID_SHA256; 1244 hash_alg_tag = SEC_OID_SHA256;
1229 break; 1245 break;
1230 case blink::WebCryptoAlgorithmIdSha384: 1246 case blink::WebCryptoAlgorithmIdSha384:
1231 hash_alg_tag = SEC_OID_SHA384; 1247 hash_alg_tag = SEC_OID_SHA384;
1232 break; 1248 break;
1233 case blink::WebCryptoAlgorithmIdSha512: 1249 case blink::WebCryptoAlgorithmIdSha512:
1234 hash_alg_tag = SEC_OID_SHA512; 1250 hash_alg_tag = SEC_OID_SHA512;
1235 break; 1251 break;
1236 default: 1252 default:
1237 return false; 1253 return Status::ErrorUnsupported();
1238 } 1254 }
1239 1255
1240 *signature_match = 1256 *signature_match =
1241 SECSuccess == VFY_VerifyDataDirect(data, 1257 SECSuccess == VFY_VerifyDataDirect(data,
1242 data_size, 1258 data_size,
1243 public_key->key(), 1259 public_key->key(),
1244 &signature_item, 1260 &signature_item,
1245 SEC_OID_PKCS1_RSA_ENCRYPTION, 1261 SEC_OID_PKCS1_RSA_ENCRYPTION,
1246 hash_alg_tag, 1262 hash_alg_tag,
1247 NULL, 1263 NULL,
1248 NULL); 1264 NULL);
1249 1265
1250 break; 1266 break;
1251 } 1267 }
1252 default: 1268 default:
1253 return false; 1269 return Status::ErrorUnsupported();
1254 } 1270 }
1255 1271
1256 return true; 1272 return Status::Success();
1257 } 1273 }
1258 1274
1259 bool WebCryptoImpl::ImportRsaPublicKeyInternal( 1275 Status WebCryptoImpl::ImportRsaPublicKeyInternal(
1260 const unsigned char* modulus_data, 1276 const unsigned char* modulus_data,
1261 unsigned modulus_size, 1277 unsigned modulus_size,
1262 const unsigned char* exponent_data, 1278 const unsigned char* exponent_data,
1263 unsigned exponent_size, 1279 unsigned exponent_size,
1264 const blink::WebCryptoAlgorithm& algorithm, 1280 const blink::WebCryptoAlgorithm& algorithm,
1265 bool extractable, 1281 bool extractable,
1266 blink::WebCryptoKeyUsageMask usage_mask, 1282 blink::WebCryptoKeyUsageMask usage_mask,
1267 blink::WebCryptoKey* key) { 1283 blink::WebCryptoKey* key) {
1268 1284
1269 if (!modulus_size || !exponent_size) 1285 if (!modulus_size)
1270 return false; 1286 return Status::ErrorImportRsaEmptyModulus();
1287
1288 if (!exponent_size)
1289 return Status::ErrorImportRsaEmptyExponent();
1290
1271 DCHECK(modulus_data); 1291 DCHECK(modulus_data);
1272 DCHECK(exponent_data); 1292 DCHECK(exponent_data);
1273 1293
1274 // NSS does not provide a way to create an RSA public key directly from the 1294 // NSS does not provide a way to create an RSA public key directly from the
1275 // modulus and exponent values, but it can import an DER-encoded ASN.1 blob 1295 // modulus and exponent values, but it can import an DER-encoded ASN.1 blob
1276 // with these values and create the public key from that. The code below 1296 // with these values and create the public key from that. The code below
1277 // follows the recommendation described in 1297 // follows the recommendation described in
1278 // https://developer.mozilla.org/en-US/docs/NSS/NSS_Tech_Notes/nss_tech_note7 1298 // https://developer.mozilla.org/en-US/docs/NSS/NSS_Tech_Notes/nss_tech_note7
1279 1299
1280 // Pack the input values into a struct compatible with NSS ASN.1 encoding, and 1300 // Pack the input values into a struct compatible with NSS ASN.1 encoding, and
(...skipping 10 matching lines...) Expand all
1291 const SEC_ASN1Template rsa_public_key_template[] = { 1311 const SEC_ASN1Template rsa_public_key_template[] = {
1292 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RsaPublicKeyData)}, 1312 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RsaPublicKeyData)},
1293 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, modulus), }, 1313 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, modulus), },
1294 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, exponent), }, 1314 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, exponent), },
1295 {0, }}; 1315 {0, }};
1296 1316
1297 // DER-encode the public key. 1317 // DER-encode the public key.
1298 crypto::ScopedSECItem pubkey_der(SEC_ASN1EncodeItem( 1318 crypto::ScopedSECItem pubkey_der(SEC_ASN1EncodeItem(
1299 NULL, NULL, &pubkey_in, rsa_public_key_template)); 1319 NULL, NULL, &pubkey_in, rsa_public_key_template));
1300 if (!pubkey_der) 1320 if (!pubkey_der)
1301 return false; 1321 return Status::Error();
1302 1322
1303 // Import the DER-encoded public key to create an RSA SECKEYPublicKey. 1323 // Import the DER-encoded public key to create an RSA SECKEYPublicKey.
1304 crypto::ScopedSECKEYPublicKey pubkey( 1324 crypto::ScopedSECKEYPublicKey pubkey(
1305 SECKEY_ImportDERPublicKey(pubkey_der.get(), CKK_RSA)); 1325 SECKEY_ImportDERPublicKey(pubkey_der.get(), CKK_RSA));
1306 if (!pubkey) 1326 if (!pubkey)
1307 return false; 1327 return Status::Error();
1308 1328
1309 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), 1329 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()),
1310 blink::WebCryptoKeyTypePublic, 1330 blink::WebCryptoKeyTypePublic,
1311 extractable, 1331 extractable,
1312 algorithm, 1332 algorithm,
1313 usage_mask); 1333 usage_mask);
1314 return true; 1334 return Status::Success();
1315 } 1335 }
1316 1336
1317 } // namespace content 1337 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698