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