Index: content/renderer/webcrypto/webcrypto_impl_nss.cc |
diff --git a/content/renderer/webcrypto/webcrypto_impl_nss.cc b/content/renderer/webcrypto/webcrypto_impl_nss.cc |
index 6a62cb8f88f047954913a3468fe20b2601af489e..82361fb44a2376a9dce68414103b9d4c5dc15f3d 100644 |
--- a/content/renderer/webcrypto/webcrypto_impl_nss.cc |
+++ b/content/renderer/webcrypto/webcrypto_impl_nss.cc |
@@ -84,23 +84,17 @@ void ShrinkBuffer(WebKit::WebArrayBuffer* buffer, unsigned new_size) { |
*buffer = new_buffer; |
} |
-} // namespace |
- |
-void WebCryptoImpl::Init() { |
- crypto::EnsureNSSInit(); |
-} |
- |
-bool WebCryptoImpl::EncryptInternal( |
+bool AesCbcEncryptDecrypt( |
+ CK_ATTRIBUTE_TYPE operation, |
const WebKit::WebCryptoAlgorithm& algorithm, |
const WebKit::WebCryptoKey& key, |
const unsigned char* data, |
unsigned data_size, |
WebKit::WebArrayBuffer* buffer) { |
- if (algorithm.id() != WebKit::WebCryptoAlgorithmIdAesCbc) |
- return false; |
- |
+ DCHECK_EQ(WebKit::WebCryptoAlgorithmIdAesCbc, algorithm.id()); |
DCHECK_EQ(algorithm.id(), key.algorithm().id()); |
DCHECK_EQ(WebKit::WebCryptoKeyTypeSecret, key.type()); |
+ DCHECK(operation == CKA_ENCRYPT || operation == CKA_DECRYPT); |
SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); |
@@ -118,7 +112,7 @@ bool WebCryptoImpl::EncryptInternal( |
return false; |
crypto::ScopedPK11Context context(PK11_CreateContextBySymKey( |
- CKM_AES_CBC_PAD, CKA_ENCRYPT, sym_key->key(), param.get())); |
+ CKM_AES_CBC_PAD, operation, sym_key->key(), param.get())); |
if (!context.get()) |
return false; |
@@ -133,6 +127,16 @@ bool WebCryptoImpl::EncryptInternal( |
return false; |
} |
+ // PK11_CipherOp does an invalid memory access when given empty decryption |
+ // input, or input which is not a multiple of the block size. See also |
+ // https://bugzilla.mozilla.com/show_bug.cgi?id=921687. |
+ if (operation == CKA_DECRYPT && |
+ (data_size == 0 || (data_size % AES_BLOCK_SIZE != 0))) { |
+ return false; |
+ } |
+ |
+ // TODO(eroman): Refine the output buffer size. It can be computed exactly for |
+ // encryption, and can be smaller for decryption. |
unsigned output_max_len = data_size + AES_BLOCK_SIZE; |
CHECK_GT(output_max_len, data_size); |
@@ -162,6 +166,40 @@ bool WebCryptoImpl::EncryptInternal( |
return true; |
} |
+} // namespace |
+ |
+void WebCryptoImpl::Init() { |
+ crypto::EnsureNSSInit(); |
+} |
+ |
+bool WebCryptoImpl::EncryptInternal( |
+ const WebKit::WebCryptoAlgorithm& algorithm, |
+ const WebKit::WebCryptoKey& key, |
+ const unsigned char* data, |
+ unsigned data_size, |
+ WebKit::WebArrayBuffer* buffer) { |
+ if (algorithm.id() == WebKit::WebCryptoAlgorithmIdAesCbc) { |
+ return AesCbcEncryptDecrypt( |
+ CKA_ENCRYPT, algorithm, key, data, data_size, buffer); |
+ } |
+ |
+ return false; |
+} |
+ |
+bool WebCryptoImpl::DecryptInternal( |
+ const WebKit::WebCryptoAlgorithm& algorithm, |
+ const WebKit::WebCryptoKey& key, |
+ const unsigned char* data, |
+ unsigned data_size, |
+ WebKit::WebArrayBuffer* buffer) { |
+ if (algorithm.id() == WebKit::WebCryptoAlgorithmIdAesCbc) { |
+ return AesCbcEncryptDecrypt( |
+ CKA_DECRYPT, algorithm, key, data, data_size, buffer); |
+ } |
+ |
+ return false; |
+} |
+ |
bool WebCryptoImpl::DigestInternal( |
const WebKit::WebCryptoAlgorithm& algorithm, |
const unsigned char* data, |