OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/platform_crypto.h" | 5 #include "content/renderer/webcrypto/platform_crypto.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 #include <openssl/aes.h> | 8 #include <openssl/aes.h> |
9 #include <openssl/evp.h> | 9 #include <openssl/evp.h> |
10 #include <openssl/hmac.h> | 10 #include <openssl/hmac.h> |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 case 24: | 52 case 24: |
53 return EVP_aes_192_cbc(); | 53 return EVP_aes_192_cbc(); |
54 case 32: | 54 case 32: |
55 return EVP_aes_256_cbc(); | 55 return EVP_aes_256_cbc(); |
56 default: | 56 default: |
57 return NULL; | 57 return NULL; |
58 } | 58 } |
59 } | 59 } |
60 | 60 |
61 // OpenSSL constants for EVP_CipherInit_ex(), do not change | 61 // OpenSSL constants for EVP_CipherInit_ex(), do not change |
62 enum CipherOperation { | 62 enum CipherOperation { kDoDecrypt = 0, kDoEncrypt = 1 }; |
63 kDoDecrypt = 0, | |
64 kDoEncrypt = 1 | |
65 }; | |
66 | 63 |
67 Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode, | 64 Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode, |
68 SymKey* key, | 65 SymKey* key, |
69 const CryptoData& iv, | 66 const CryptoData& iv, |
70 const CryptoData& data, | 67 const CryptoData& data, |
71 blink::WebArrayBuffer* buffer) { | 68 blink::WebArrayBuffer* buffer) { |
72 CipherOperation cipher_operation = | 69 CipherOperation cipher_operation = |
73 (mode == ENCRYPT) ? kDoEncrypt : kDoDecrypt; | 70 (mode == ENCRYPT) ? kDoEncrypt : kDoDecrypt; |
74 | 71 |
75 if (data.byte_length() >= INT_MAX - AES_BLOCK_SIZE) { | 72 if (data.byte_length() >= INT_MAX - AES_BLOCK_SIZE) { |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 return Status::Success(); | 132 return Status::Success(); |
136 } | 133 } |
137 | 134 |
138 } // namespace | 135 } // namespace |
139 | 136 |
140 Status ExportKeyRaw(SymKey* key, blink::WebArrayBuffer* buffer) { | 137 Status ExportKeyRaw(SymKey* key, blink::WebArrayBuffer* buffer) { |
141 *buffer = CreateArrayBuffer(Uint8VectorStart(key->key()), key->key().size()); | 138 *buffer = CreateArrayBuffer(Uint8VectorStart(key->key()), key->key().size()); |
142 return Status::Success(); | 139 return Status::Success(); |
143 } | 140 } |
144 | 141 |
145 void Init() { | 142 void Init() { crypto::EnsureOpenSSLInit(); } |
146 crypto::EnsureOpenSSLInit(); | |
147 } | |
148 | 143 |
149 Status EncryptDecryptAesCbc(EncryptOrDecrypt mode, | 144 Status EncryptDecryptAesCbc(EncryptOrDecrypt mode, |
150 SymKey* key, | 145 SymKey* key, |
151 const CryptoData& data, | 146 const CryptoData& data, |
152 const CryptoData& iv, | 147 const CryptoData& iv, |
153 blink::WebArrayBuffer* buffer) { | 148 blink::WebArrayBuffer* buffer) { |
154 // TODO(eroman): inline the function here. | 149 // TODO(eroman): inline the function here. |
155 return AesCbcEncryptDecrypt(mode, key, iv, data, buffer); | 150 return AesCbcEncryptDecrypt(mode, key, iv, data, buffer); |
156 } | 151 } |
157 | 152 |
(...skipping 24 matching lines...) Expand all Loading... |
182 return Status::ErrorUnexpected(); | 177 return Status::ErrorUnexpected(); |
183 } | 178 } |
184 | 179 |
185 crypto::ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> digest_context( | 180 crypto::ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> digest_context( |
186 EVP_MD_CTX_create()); | 181 EVP_MD_CTX_create()); |
187 if (!digest_context.get()) | 182 if (!digest_context.get()) |
188 return Status::Error(); | 183 return Status::Error(); |
189 | 184 |
190 if (!EVP_DigestInit_ex(digest_context.get(), digest_algorithm, NULL) || | 185 if (!EVP_DigestInit_ex(digest_context.get(), digest_algorithm, NULL) || |
191 !EVP_DigestUpdate( | 186 !EVP_DigestUpdate( |
192 digest_context.get(), data.bytes(), data.byte_length())) { | 187 digest_context.get(), data.bytes(), data.byte_length())) { |
193 return Status::Error(); | 188 return Status::Error(); |
194 } | 189 } |
195 | 190 |
196 const int hash_expected_size = EVP_MD_CTX_size(digest_context.get()); | 191 const int hash_expected_size = EVP_MD_CTX_size(digest_context.get()); |
197 if (hash_expected_size <= 0) | 192 if (hash_expected_size <= 0) |
198 return Status::ErrorUnexpected(); | 193 return Status::ErrorUnexpected(); |
199 DCHECK_LE(hash_expected_size, EVP_MAX_MD_SIZE); | 194 DCHECK_LE(hash_expected_size, EVP_MAX_MD_SIZE); |
200 | 195 |
201 *buffer = blink::WebArrayBuffer::create(hash_expected_size, 1); | 196 *buffer = blink::WebArrayBuffer::create(hash_expected_size, 1); |
202 unsigned char* const hash_buffer = | 197 unsigned char* const hash_buffer = |
203 reinterpret_cast<unsigned char* const>(buffer->data()); | 198 reinterpret_cast<unsigned char* const>(buffer->data()); |
204 | 199 |
205 unsigned int hash_size = 0; | 200 unsigned int hash_size = 0; |
206 if (!EVP_DigestFinal_ex(digest_context.get(), hash_buffer, &hash_size) || | 201 if (!EVP_DigestFinal_ex(digest_context.get(), hash_buffer, &hash_size) || |
207 static_cast<int>(hash_size) != hash_expected_size) { | 202 static_cast<int>(hash_size) != hash_expected_size) { |
208 buffer->reset(); | 203 buffer->reset(); |
209 return Status::Error(); | 204 return Status::Error(); |
210 } | 205 } |
211 | 206 |
212 return Status::Success(); | 207 return Status::Success(); |
213 } | 208 } |
214 | 209 |
215 Status GenerateSecretKey( | 210 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, |
216 const blink::WebCryptoAlgorithm& algorithm, | 211 bool extractable, |
217 bool extractable, | 212 blink::WebCryptoKeyUsageMask usage_mask, |
218 blink::WebCryptoKeyUsageMask usage_mask, | 213 unsigned keylen_bytes, |
219 unsigned keylen_bytes, | 214 blink::WebCryptoKey* key) { |
220 blink::WebCryptoKey* key) { | |
221 // TODO(eroman): Is this right? | 215 // TODO(eroman): Is this right? |
222 if (keylen_bytes == 0) | 216 if (keylen_bytes == 0) |
223 return Status::ErrorGenerateKeyLength(); | 217 return Status::ErrorGenerateKeyLength(); |
224 | 218 |
225 crypto::OpenSSLErrStackTracer(FROM_HERE); | 219 crypto::OpenSSLErrStackTracer(FROM_HERE); |
226 | 220 |
227 std::vector<unsigned char> random_bytes(keylen_bytes, 0); | 221 std::vector<unsigned char> random_bytes(keylen_bytes, 0); |
228 if (!(RAND_bytes(&random_bytes[0], keylen_bytes))) | 222 if (!(RAND_bytes(&random_bytes[0], keylen_bytes))) |
229 return Status::Error(); | 223 return Status::Error(); |
230 | 224 |
231 *key = blink::WebCryptoKey::create(new SymKey(CryptoData(random_bytes)), | 225 *key = blink::WebCryptoKey::create(new SymKey(CryptoData(random_bytes)), |
232 blink::WebCryptoKeyTypeSecret, | 226 blink::WebCryptoKeyTypeSecret, |
233 extractable, | 227 extractable, |
234 algorithm, | 228 algorithm, |
235 usage_mask); | 229 usage_mask); |
236 | 230 |
237 return Status::Success(); | 231 return Status::Success(); |
238 } | 232 } |
239 | 233 |
240 Status GenerateRsaKeyPair( | 234 Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm, |
241 const blink::WebCryptoAlgorithm& algorithm, | 235 bool extractable, |
242 bool extractable, | 236 blink::WebCryptoKeyUsageMask usage_mask, |
243 blink::WebCryptoKeyUsageMask usage_mask, | 237 blink::WebCryptoKey* public_key, |
244 blink::WebCryptoKey* public_key, | 238 blink::WebCryptoKey* private_key) { |
245 blink::WebCryptoKey* private_key) { | |
246 // TODO(padolph): Placeholder for OpenSSL implementation. | 239 // TODO(padolph): Placeholder for OpenSSL implementation. |
247 // Issue http://crbug.com/267888. | 240 // Issue http://crbug.com/267888. |
248 return Status::ErrorUnsupported(); | 241 return Status::ErrorUnsupported(); |
249 } | 242 } |
250 | 243 |
251 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, | 244 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, |
252 const CryptoData& key_data, | 245 const CryptoData& key_data, |
253 bool extractable, | 246 bool extractable, |
254 blink::WebCryptoKeyUsageMask usage_mask, | 247 blink::WebCryptoKeyUsageMask usage_mask, |
255 blink::WebCryptoKey* key) { | 248 blink::WebCryptoKey* key) { |
256 *key = blink::WebCryptoKey::create(new SymKey(key_data), | 249 *key = blink::WebCryptoKey::create(new SymKey(key_data), |
257 blink::WebCryptoKeyTypeSecret, | 250 blink::WebCryptoKeyTypeSecret, |
258 extractable, | 251 extractable, |
259 algorithm, | 252 algorithm, |
260 usage_mask); | 253 usage_mask); |
261 | 254 |
262 return Status::Success(); | 255 return Status::Success(); |
263 } | 256 } |
264 | 257 |
265 Status SignHmac(SymKey* key, | 258 Status SignHmac(SymKey* key, |
266 const blink::WebCryptoAlgorithm& hash, | 259 const blink::WebCryptoAlgorithm& hash, |
267 const CryptoData& data, | 260 const CryptoData& data, |
268 blink::WebArrayBuffer* buffer) { | 261 blink::WebArrayBuffer* buffer) { |
269 blink::WebArrayBuffer result; | 262 blink::WebArrayBuffer result; |
270 | 263 |
271 // TODO(eroman): De-indent this code. | 264 const EVP_MD* evp_sha = 0; |
272 const EVP_MD* evp_sha = 0; | 265 unsigned int hmac_expected_length = 0; |
273 unsigned int hmac_expected_length = 0; | 266 // Note that HMAC length is determined by the hash used. |
274 // Note that HMAC length is determined by the hash used. | 267 switch (hash.id()) { |
275 switch (hash.id()) { | 268 case blink::WebCryptoAlgorithmIdSha1: |
276 case blink::WebCryptoAlgorithmIdSha1: | 269 evp_sha = EVP_sha1(); |
277 evp_sha = EVP_sha1(); | 270 hmac_expected_length = SHA_DIGEST_LENGTH; |
278 hmac_expected_length = SHA_DIGEST_LENGTH; | 271 break; |
279 break; | 272 case blink::WebCryptoAlgorithmIdSha224: |
280 case blink::WebCryptoAlgorithmIdSha224: | 273 evp_sha = EVP_sha224(); |
281 evp_sha = EVP_sha224(); | 274 hmac_expected_length = SHA224_DIGEST_LENGTH; |
282 hmac_expected_length = SHA224_DIGEST_LENGTH; | 275 break; |
283 break; | 276 case blink::WebCryptoAlgorithmIdSha256: |
284 case blink::WebCryptoAlgorithmIdSha256: | 277 evp_sha = EVP_sha256(); |
285 evp_sha = EVP_sha256(); | 278 hmac_expected_length = SHA256_DIGEST_LENGTH; |
286 hmac_expected_length = SHA256_DIGEST_LENGTH; | 279 break; |
287 break; | 280 case blink::WebCryptoAlgorithmIdSha384: |
288 case blink::WebCryptoAlgorithmIdSha384: | 281 evp_sha = EVP_sha384(); |
289 evp_sha = EVP_sha384(); | 282 hmac_expected_length = SHA384_DIGEST_LENGTH; |
290 hmac_expected_length = SHA384_DIGEST_LENGTH; | 283 break; |
291 break; | 284 case blink::WebCryptoAlgorithmIdSha512: |
292 case blink::WebCryptoAlgorithmIdSha512: | 285 evp_sha = EVP_sha512(); |
293 evp_sha = EVP_sha512(); | 286 hmac_expected_length = SHA512_DIGEST_LENGTH; |
294 hmac_expected_length = SHA512_DIGEST_LENGTH; | 287 break; |
295 break; | 288 default: |
296 default: | 289 // Not a digest algorithm. |
297 // Not a digest algorithm. | 290 return Status::ErrorUnsupported(); |
298 return Status::ErrorUnsupported(); | 291 } |
299 } | |
300 | 292 |
301 const std::vector<unsigned char>& raw_key = key->key(); | 293 const std::vector<unsigned char>& raw_key = key->key(); |
302 | 294 |
303 // OpenSSL wierdness here. | 295 // OpenSSL wierdness here. |
304 // First, HMAC() needs a void* for the key data, so make one up front as a | 296 // First, HMAC() needs a void* for the key data, so make one up front as a |
305 // cosmetic to avoid a cast. Second, OpenSSL does not like a NULL key, | 297 // cosmetic to avoid a cast. Second, OpenSSL does not like a NULL key, |
306 // which will result if the raw_key vector is empty; an entirely valid | 298 // which will result if the raw_key vector is empty; an entirely valid |
307 // case. Handle this specific case by pointing to an empty array. | 299 // case. Handle this specific case by pointing to an empty array. |
308 const unsigned char null_key[] = {}; | 300 const unsigned char null_key[] = {}; |
309 const void* const raw_key_voidp = raw_key.size() ? &raw_key[0] : null_key; | 301 const void* const raw_key_voidp = raw_key.size() ? &raw_key[0] : null_key; |
310 | 302 |
311 result = blink::WebArrayBuffer::create(hmac_expected_length, 1); | 303 result = blink::WebArrayBuffer::create(hmac_expected_length, 1); |
312 crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result( | 304 crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result( |
313 reinterpret_cast<unsigned char*>(result.data()), | 305 reinterpret_cast<unsigned char*>(result.data()), hmac_expected_length); |
314 hmac_expected_length); | |
315 | 306 |
316 crypto::OpenSSLErrStackTracer(FROM_HERE); | 307 crypto::OpenSSLErrStackTracer(FROM_HERE); |
317 | 308 |
318 unsigned int hmac_actual_length; | 309 unsigned int hmac_actual_length; |
319 unsigned char* const success = HMAC(evp_sha, | 310 unsigned char* const success = HMAC(evp_sha, |
320 raw_key_voidp, | 311 raw_key_voidp, |
321 raw_key.size(), | 312 raw_key.size(), |
322 data.bytes(), | 313 data.bytes(), |
323 data.byte_length(), | 314 data.byte_length(), |
324 hmac_result.safe_buffer(), | 315 hmac_result.safe_buffer(), |
325 &hmac_actual_length); | 316 &hmac_actual_length); |
326 if (!success || hmac_actual_length != hmac_expected_length) | 317 if (!success || hmac_actual_length != hmac_expected_length) |
327 return Status::Error(); | 318 return Status::Error(); |
328 | 319 |
329 *buffer = result; | 320 *buffer = result; |
330 return Status::Success(); | 321 return Status::Success(); |
331 } | 322 } |
332 | 323 |
333 Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm, | 324 Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm, |
334 bool extractable, | 325 bool extractable, |
335 blink::WebCryptoKeyUsageMask usage_mask, | 326 blink::WebCryptoKeyUsageMask usage_mask, |
336 const CryptoData& modulus_data, | 327 const CryptoData& modulus_data, |
337 const CryptoData& exponent_data, | 328 const CryptoData& exponent_data, |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
406 Status ExportKeySpki(PublicKey* key, blink::WebArrayBuffer* buffer) { | 397 Status ExportKeySpki(PublicKey* key, blink::WebArrayBuffer* buffer) { |
407 // TODO(eroman): http://crbug.com/267888 | 398 // TODO(eroman): http://crbug.com/267888 |
408 return Status::ErrorUnsupported(); | 399 return Status::ErrorUnsupported(); |
409 } | 400 } |
410 | 401 |
411 } // namespace platform | 402 } // namespace platform |
412 | 403 |
413 } // namespace webcrypto | 404 } // namespace webcrypto |
414 | 405 |
415 } // namespace content | 406 } // namespace content |
OLD | NEW |