OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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, ¶m, | 361 SECStatus result = func(sym_key->key(), CKM_AES_GCM, ¶m, |
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 Loading... | |
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 Loading... | |
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 ¶m_item, | 1105 ¶m_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 ¶m_item, | 1118 ¶m_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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |