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 |