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

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

Powered by Google App Engine
This is Rietveld 408576698