| 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 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 if (new_size == buffer->byteLength()) | 77 if (new_size == buffer->byteLength()) |
| 78 return; | 78 return; |
| 79 | 79 |
| 80 WebKit::WebArrayBuffer new_buffer = | 80 WebKit::WebArrayBuffer new_buffer = |
| 81 WebKit::WebArrayBuffer::create(new_size, 1); | 81 WebKit::WebArrayBuffer::create(new_size, 1); |
| 82 DCHECK(!new_buffer.isNull()); | 82 DCHECK(!new_buffer.isNull()); |
| 83 memcpy(new_buffer.data(), buffer->data(), new_size); | 83 memcpy(new_buffer.data(), buffer->data(), new_size); |
| 84 *buffer = new_buffer; | 84 *buffer = new_buffer; |
| 85 } | 85 } |
| 86 | 86 |
| 87 } // namespace | 87 bool AesCbcEncryptDecrypt( |
| 88 | 88 CK_ATTRIBUTE_TYPE operation, |
| 89 void WebCryptoImpl::Init() { | |
| 90 crypto::EnsureNSSInit(); | |
| 91 } | |
| 92 | |
| 93 bool WebCryptoImpl::EncryptInternal( | |
| 94 const WebKit::WebCryptoAlgorithm& algorithm, | 89 const WebKit::WebCryptoAlgorithm& algorithm, |
| 95 const WebKit::WebCryptoKey& key, | 90 const WebKit::WebCryptoKey& key, |
| 96 const unsigned char* data, | 91 const unsigned char* data, |
| 97 unsigned data_size, | 92 unsigned data_size, |
| 98 WebKit::WebArrayBuffer* buffer) { | 93 WebKit::WebArrayBuffer* buffer) { |
| 99 if (algorithm.id() != WebKit::WebCryptoAlgorithmIdAesCbc) | 94 DCHECK_EQ(WebKit::WebCryptoAlgorithmIdAesCbc, algorithm.id()); |
| 100 return false; | |
| 101 | |
| 102 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | 95 DCHECK_EQ(algorithm.id(), key.algorithm().id()); |
| 103 DCHECK_EQ(WebKit::WebCryptoKeyTypeSecret, key.type()); | 96 DCHECK_EQ(WebKit::WebCryptoKeyTypeSecret, key.type()); |
| 97 DCHECK(operation == CKA_ENCRYPT || operation == CKA_DECRYPT); |
| 104 | 98 |
| 105 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | 99 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); |
| 106 | 100 |
| 107 const WebKit::WebCryptoAesCbcParams* params = algorithm.aesCbcParams(); | 101 const WebKit::WebCryptoAesCbcParams* params = algorithm.aesCbcParams(); |
| 108 if (params->iv().size() != AES_BLOCK_SIZE) | 102 if (params->iv().size() != AES_BLOCK_SIZE) |
| 109 return false; | 103 return false; |
| 110 | 104 |
| 111 SECItem iv_item; | 105 SECItem iv_item; |
| 112 iv_item.type = siBuffer; | 106 iv_item.type = siBuffer; |
| 113 iv_item.data = const_cast<unsigned char*>(params->iv().data()); | 107 iv_item.data = const_cast<unsigned char*>(params->iv().data()); |
| 114 iv_item.len = params->iv().size(); | 108 iv_item.len = params->iv().size(); |
| 115 | 109 |
| 116 crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item)); | 110 crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item)); |
| 117 if (!param) | 111 if (!param) |
| 118 return false; | 112 return false; |
| 119 | 113 |
| 120 crypto::ScopedPK11Context context(PK11_CreateContextBySymKey( | 114 crypto::ScopedPK11Context context(PK11_CreateContextBySymKey( |
| 121 CKM_AES_CBC_PAD, CKA_ENCRYPT, sym_key->key(), param.get())); | 115 CKM_AES_CBC_PAD, operation, sym_key->key(), param.get())); |
| 122 | 116 |
| 123 if (!context.get()) | 117 if (!context.get()) |
| 124 return false; | 118 return false; |
| 125 | 119 |
| 126 // Oddly PK11_CipherOp takes input and output lenths as "int" rather than | 120 // Oddly PK11_CipherOp takes input and output lenths as "int" rather than |
| 127 // "unsigned". Do some checks now to avoid integer overflowing. | 121 // "unsigned". Do some checks now to avoid integer overflowing. |
| 128 if (data_size >= INT_MAX - AES_BLOCK_SIZE) { | 122 if (data_size >= INT_MAX - AES_BLOCK_SIZE) { |
| 129 // TODO(eroman): Handle this by chunking the input fed into NSS. Right now | 123 // TODO(eroman): Handle this by chunking the input fed into NSS. Right now |
| 130 // it doesn't make much difference since the one-shot API would end up | 124 // it doesn't make much difference since the one-shot API would end up |
| 131 // blowing out the memory and crashing anyway. However a newer version of | 125 // blowing out the memory and crashing anyway. However a newer version of |
| 132 // the spec allows for a sequence<CryptoData> so this will be relevant. | 126 // the spec allows for a sequence<CryptoData> so this will be relevant. |
| 133 return false; | 127 return false; |
| 134 } | 128 } |
| 135 | 129 |
| 130 // PK11_CipherOp does an invalid memory access when given empty decryption |
| 131 // input, or input which is not a multiple of the block size. See also |
| 132 // https://bugzilla.mozilla.com/show_bug.cgi?id=921687. |
| 133 if (operation == CKA_DECRYPT && |
| 134 (data_size == 0 || (data_size % AES_BLOCK_SIZE != 0))) { |
| 135 return false; |
| 136 } |
| 137 |
| 138 // TODO(eroman): Refine the output buffer size. It can be computed exactly for |
| 139 // encryption, and can be smaller for decryption. |
| 136 unsigned output_max_len = data_size + AES_BLOCK_SIZE; | 140 unsigned output_max_len = data_size + AES_BLOCK_SIZE; |
| 137 CHECK_GT(output_max_len, data_size); | 141 CHECK_GT(output_max_len, data_size); |
| 138 | 142 |
| 139 *buffer = WebKit::WebArrayBuffer::create(output_max_len, 1); | 143 *buffer = WebKit::WebArrayBuffer::create(output_max_len, 1); |
| 140 | 144 |
| 141 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); | 145 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); |
| 142 | 146 |
| 143 int output_len; | 147 int output_len; |
| 144 if (SECSuccess != PK11_CipherOp(context.get(), | 148 if (SECSuccess != PK11_CipherOp(context.get(), |
| 145 buffer_data, | 149 buffer_data, |
| 146 &output_len, | 150 &output_len, |
| 147 buffer->byteLength(), | 151 buffer->byteLength(), |
| 148 data, | 152 data, |
| 149 data_size)) { | 153 data_size)) { |
| 150 return false; | 154 return false; |
| 151 } | 155 } |
| 152 | 156 |
| 153 unsigned int final_output_chunk_len; | 157 unsigned int final_output_chunk_len; |
| 154 if (SECSuccess != PK11_DigestFinal(context.get(), | 158 if (SECSuccess != PK11_DigestFinal(context.get(), |
| 155 buffer_data + output_len, | 159 buffer_data + output_len, |
| 156 &final_output_chunk_len, | 160 &final_output_chunk_len, |
| 157 output_max_len - output_len)) { | 161 output_max_len - output_len)) { |
| 158 return false; | 162 return false; |
| 159 } | 163 } |
| 160 | 164 |
| 161 ShrinkBuffer(buffer, final_output_chunk_len + output_len); | 165 ShrinkBuffer(buffer, final_output_chunk_len + output_len); |
| 162 return true; | 166 return true; |
| 163 } | 167 } |
| 164 | 168 |
| 169 } // namespace |
| 170 |
| 171 void WebCryptoImpl::Init() { |
| 172 crypto::EnsureNSSInit(); |
| 173 } |
| 174 |
| 175 bool WebCryptoImpl::EncryptInternal( |
| 176 const WebKit::WebCryptoAlgorithm& algorithm, |
| 177 const WebKit::WebCryptoKey& key, |
| 178 const unsigned char* data, |
| 179 unsigned data_size, |
| 180 WebKit::WebArrayBuffer* buffer) { |
| 181 if (algorithm.id() == WebKit::WebCryptoAlgorithmIdAesCbc) { |
| 182 return AesCbcEncryptDecrypt( |
| 183 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); |
| 184 } |
| 185 |
| 186 return false; |
| 187 } |
| 188 |
| 189 bool WebCryptoImpl::DecryptInternal( |
| 190 const WebKit::WebCryptoAlgorithm& algorithm, |
| 191 const WebKit::WebCryptoKey& key, |
| 192 const unsigned char* data, |
| 193 unsigned data_size, |
| 194 WebKit::WebArrayBuffer* buffer) { |
| 195 if (algorithm.id() == WebKit::WebCryptoAlgorithmIdAesCbc) { |
| 196 return AesCbcEncryptDecrypt( |
| 197 CKA_DECRYPT, algorithm, key, data, data_size, buffer); |
| 198 } |
| 199 |
| 200 return false; |
| 201 } |
| 202 |
| 165 bool WebCryptoImpl::DigestInternal( | 203 bool WebCryptoImpl::DigestInternal( |
| 166 const WebKit::WebCryptoAlgorithm& algorithm, | 204 const WebKit::WebCryptoAlgorithm& algorithm, |
| 167 const unsigned char* data, | 205 const unsigned char* data, |
| 168 unsigned data_size, | 206 unsigned data_size, |
| 169 WebKit::WebArrayBuffer* buffer) { | 207 WebKit::WebArrayBuffer* buffer) { |
| 170 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm); | 208 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm); |
| 171 if (hash_type == HASH_AlgNULL) { | 209 if (hash_type == HASH_AlgNULL) { |
| 172 return false; | 210 return false; |
| 173 } | 211 } |
| 174 | 212 |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 371 break; | 409 break; |
| 372 } | 410 } |
| 373 default: | 411 default: |
| 374 return false; | 412 return false; |
| 375 } | 413 } |
| 376 | 414 |
| 377 return true; | 415 return true; |
| 378 } | 416 } |
| 379 | 417 |
| 380 } // namespace content | 418 } // namespace content |
| OLD | NEW |