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 <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> |
11 #include <openssl/sha.h> | 11 #include <openssl/sha.h> |
12 #include <openssl/evp.h> | 12 #include <openssl/evp.h> |
13 #include <openssl/rand.h> | 13 #include <openssl/rand.h> |
14 | 14 |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "crypto/openssl_util.h" | 16 #include "crypto/openssl_util.h" |
17 #include "crypto/secure_util.h" | 17 #include "crypto/secure_util.h" |
18 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" | 18 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" |
19 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 19 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | 20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |
21 | 21 |
22 namespace content { | 22 namespace content { |
23 | 23 |
24 namespace { | 24 namespace { |
25 | 25 |
26 class SymKeyHandle : public WebKit::WebCryptoKeyHandle { | 26 class SymKeyHandle : public blink::WebCryptoKeyHandle { |
27 public: | 27 public: |
28 SymKeyHandle(const unsigned char* key_data, unsigned key_data_size) | 28 SymKeyHandle(const unsigned char* key_data, unsigned key_data_size) |
29 : key_(key_data, key_data + key_data_size) {} | 29 : key_(key_data, key_data + key_data_size) {} |
30 | 30 |
31 const std::vector<unsigned char>& key() const { return key_; } | 31 const std::vector<unsigned char>& key() const { return key_; } |
32 | 32 |
33 private: | 33 private: |
34 const std::vector<unsigned char> key_; | 34 const std::vector<unsigned char> key_; |
35 | 35 |
36 DISALLOW_COPY_AND_ASSIGN(SymKeyHandle); | 36 DISALLOW_COPY_AND_ASSIGN(SymKeyHandle); |
37 }; | 37 }; |
38 | 38 |
39 const EVP_CIPHER* GetAESCipherByKeyLength(unsigned key_length_bytes) { | 39 const EVP_CIPHER* GetAESCipherByKeyLength(unsigned key_length_bytes) { |
40 // OpenSSL supports AES CBC ciphers for only 3 key lengths: 128, 192, 256 bits | 40 // OpenSSL supports AES CBC ciphers for only 3 key lengths: 128, 192, 256 bits |
41 switch (key_length_bytes) { | 41 switch (key_length_bytes) { |
42 case 16: | 42 case 16: |
43 return EVP_aes_128_cbc(); | 43 return EVP_aes_128_cbc(); |
44 case 24: | 44 case 24: |
45 return EVP_aes_192_cbc(); | 45 return EVP_aes_192_cbc(); |
46 case 32: | 46 case 32: |
47 return EVP_aes_256_cbc(); | 47 return EVP_aes_256_cbc(); |
48 default: | 48 default: |
49 return NULL; | 49 return NULL; |
50 } | 50 } |
51 } | 51 } |
52 | 52 |
53 unsigned WebCryptoHmacParamsToBlockSize( | 53 unsigned WebCryptoHmacParamsToBlockSize( |
54 const WebKit::WebCryptoHmacKeyParams* params) { | 54 const blink::WebCryptoHmacKeyParams* params) { |
55 DCHECK(params); | 55 DCHECK(params); |
56 switch (params->hash().id()) { | 56 switch (params->hash().id()) { |
57 case WebKit::WebCryptoAlgorithmIdSha1: | 57 case blink::WebCryptoAlgorithmIdSha1: |
58 return SHA_DIGEST_LENGTH / 8; | 58 return SHA_DIGEST_LENGTH / 8; |
59 case WebKit::WebCryptoAlgorithmIdSha224: | 59 case blink::WebCryptoAlgorithmIdSha224: |
60 return SHA224_DIGEST_LENGTH / 8; | 60 return SHA224_DIGEST_LENGTH / 8; |
61 case WebKit::WebCryptoAlgorithmIdSha256: | 61 case blink::WebCryptoAlgorithmIdSha256: |
62 return SHA256_DIGEST_LENGTH / 8; | 62 return SHA256_DIGEST_LENGTH / 8; |
63 case WebKit::WebCryptoAlgorithmIdSha384: | 63 case blink::WebCryptoAlgorithmIdSha384: |
64 return SHA384_DIGEST_LENGTH / 8; | 64 return SHA384_DIGEST_LENGTH / 8; |
65 case WebKit::WebCryptoAlgorithmIdSha512: | 65 case blink::WebCryptoAlgorithmIdSha512: |
66 return SHA512_DIGEST_LENGTH / 8; | 66 return SHA512_DIGEST_LENGTH / 8; |
67 default: | 67 default: |
68 return 0; | 68 return 0; |
69 } | 69 } |
70 } | 70 } |
71 | 71 |
72 // OpenSSL constants for EVP_CipherInit_ex(), do not change | 72 // OpenSSL constants for EVP_CipherInit_ex(), do not change |
73 enum CipherOperation { | 73 enum CipherOperation { |
74 kDoDecrypt = 0, | 74 kDoDecrypt = 0, |
75 kDoEncrypt = 1 | 75 kDoEncrypt = 1 |
76 }; | 76 }; |
77 | 77 |
78 bool AesCbcEncryptDecrypt(CipherOperation cipher_operation, | 78 bool AesCbcEncryptDecrypt(CipherOperation cipher_operation, |
79 const WebKit::WebCryptoAlgorithm& algorithm, | 79 const blink::WebCryptoAlgorithm& algorithm, |
80 const WebKit::WebCryptoKey& key, | 80 const blink::WebCryptoKey& key, |
81 const unsigned char* data, | 81 const unsigned char* data, |
82 unsigned data_size, | 82 unsigned data_size, |
83 WebKit::WebArrayBuffer* buffer) { | 83 blink::WebArrayBuffer* buffer) { |
84 | 84 |
85 // TODO(padolph): Handle other encrypt operations and then remove this gate | 85 // TODO(padolph): Handle other encrypt operations and then remove this gate |
86 if (algorithm.id() != WebKit::WebCryptoAlgorithmIdAesCbc) | 86 if (algorithm.id() != blink::WebCryptoAlgorithmIdAesCbc) |
87 return false; | 87 return false; |
88 | 88 |
89 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | 89 DCHECK_EQ(algorithm.id(), key.algorithm().id()); |
90 DCHECK_EQ(WebKit::WebCryptoKeyTypeSecret, key.type()); | 90 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
91 | 91 |
92 if (data_size >= INT_MAX - AES_BLOCK_SIZE) { | 92 if (data_size >= INT_MAX - AES_BLOCK_SIZE) { |
93 // TODO(padolph): Handle this by chunking the input fed into OpenSSL. Right | 93 // TODO(padolph): Handle this by chunking the input fed into OpenSSL. Right |
94 // now it doesn't make much difference since the one-shot API would end up | 94 // now it doesn't make much difference since the one-shot API would end up |
95 // blowing out the memory and crashing anyway. However a newer version of | 95 // blowing out the memory and crashing anyway. However a newer version of |
96 // the spec allows for a sequence<CryptoData> so this will be relevant. | 96 // the spec allows for a sequence<CryptoData> so this will be relevant. |
97 return false; | 97 return false; |
98 } | 98 } |
99 | 99 |
100 // Note: PKCS padding is enabled by default | 100 // Note: PKCS padding is enabled by default |
101 crypto::ScopedOpenSSL<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free> context( | 101 crypto::ScopedOpenSSL<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free> context( |
102 EVP_CIPHER_CTX_new()); | 102 EVP_CIPHER_CTX_new()); |
103 | 103 |
104 if (!context.get()) | 104 if (!context.get()) |
105 return false; | 105 return false; |
106 | 106 |
107 SymKeyHandle* const sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | 107 SymKeyHandle* const sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); |
108 | 108 |
109 const EVP_CIPHER* const cipher = | 109 const EVP_CIPHER* const cipher = |
110 GetAESCipherByKeyLength(sym_key->key().size()); | 110 GetAESCipherByKeyLength(sym_key->key().size()); |
111 DCHECK(cipher); | 111 DCHECK(cipher); |
112 | 112 |
113 const WebKit::WebCryptoAesCbcParams* const params = algorithm.aesCbcParams(); | 113 const blink::WebCryptoAesCbcParams* const params = algorithm.aesCbcParams(); |
114 if (params->iv().size() != AES_BLOCK_SIZE) | 114 if (params->iv().size() != AES_BLOCK_SIZE) |
115 return false; | 115 return false; |
116 | 116 |
117 if (!EVP_CipherInit_ex(context.get(), | 117 if (!EVP_CipherInit_ex(context.get(), |
118 cipher, | 118 cipher, |
119 NULL, | 119 NULL, |
120 &sym_key->key()[0], | 120 &sym_key->key()[0], |
121 params->iv().data(), | 121 params->iv().data(), |
122 cipher_operation)) { | 122 cipher_operation)) { |
123 return false; | 123 return false; |
124 } | 124 } |
125 | 125 |
126 // According to the openssl docs, the amount of data written may be as large | 126 // According to the openssl docs, the amount of data written may be as large |
127 // as (data_size + cipher_block_size - 1), constrained to a multiple of | 127 // as (data_size + cipher_block_size - 1), constrained to a multiple of |
128 // cipher_block_size. | 128 // cipher_block_size. |
129 unsigned output_max_len = data_size + AES_BLOCK_SIZE - 1; | 129 unsigned output_max_len = data_size + AES_BLOCK_SIZE - 1; |
130 const unsigned remainder = output_max_len % AES_BLOCK_SIZE; | 130 const unsigned remainder = output_max_len % AES_BLOCK_SIZE; |
131 if (remainder != 0) | 131 if (remainder != 0) |
132 output_max_len += AES_BLOCK_SIZE - remainder; | 132 output_max_len += AES_BLOCK_SIZE - remainder; |
133 DCHECK_GT(output_max_len, data_size); | 133 DCHECK_GT(output_max_len, data_size); |
134 | 134 |
135 *buffer = WebKit::WebArrayBuffer::create(output_max_len, 1); | 135 *buffer = blink::WebArrayBuffer::create(output_max_len, 1); |
136 | 136 |
137 unsigned char* const buffer_data = | 137 unsigned char* const buffer_data = |
138 reinterpret_cast<unsigned char*>(buffer->data()); | 138 reinterpret_cast<unsigned char*>(buffer->data()); |
139 | 139 |
140 int output_len = 0; | 140 int output_len = 0; |
141 if (!EVP_CipherUpdate( | 141 if (!EVP_CipherUpdate( |
142 context.get(), buffer_data, &output_len, data, data_size)) | 142 context.get(), buffer_data, &output_len, data, data_size)) |
143 return false; | 143 return false; |
144 int final_output_chunk_len = 0; | 144 int final_output_chunk_len = 0; |
145 if (!EVP_CipherFinal_ex( | 145 if (!EVP_CipherFinal_ex( |
146 context.get(), buffer_data + output_len, &final_output_chunk_len)) | 146 context.get(), buffer_data + output_len, &final_output_chunk_len)) |
147 return false; | 147 return false; |
148 | 148 |
149 const unsigned final_output_len = | 149 const unsigned final_output_len = |
150 static_cast<unsigned>(output_len) + | 150 static_cast<unsigned>(output_len) + |
151 static_cast<unsigned>(final_output_chunk_len); | 151 static_cast<unsigned>(final_output_chunk_len); |
152 DCHECK_LE(final_output_len, output_max_len); | 152 DCHECK_LE(final_output_len, output_max_len); |
153 | 153 |
154 WebCryptoImpl::ShrinkBuffer(buffer, final_output_len); | 154 WebCryptoImpl::ShrinkBuffer(buffer, final_output_len); |
155 | 155 |
156 return true; | 156 return true; |
157 } | 157 } |
158 | 158 |
159 } // namespace | 159 } // namespace |
160 | 160 |
161 void WebCryptoImpl::Init() { crypto::EnsureOpenSSLInit(); } | 161 void WebCryptoImpl::Init() { crypto::EnsureOpenSSLInit(); } |
162 | 162 |
163 bool WebCryptoImpl::EncryptInternal(const WebKit::WebCryptoAlgorithm& algorithm, | 163 bool WebCryptoImpl::EncryptInternal(const blink::WebCryptoAlgorithm& algorithm, |
164 const WebKit::WebCryptoKey& key, | 164 const blink::WebCryptoKey& key, |
165 const unsigned char* data, | 165 const unsigned char* data, |
166 unsigned data_size, | 166 unsigned data_size, |
167 WebKit::WebArrayBuffer* buffer) { | 167 blink::WebArrayBuffer* buffer) { |
168 if (algorithm.id() == WebKit::WebCryptoAlgorithmIdAesCbc) { | 168 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { |
169 return AesCbcEncryptDecrypt( | 169 return AesCbcEncryptDecrypt( |
170 kDoEncrypt, algorithm, key, data, data_size, buffer); | 170 kDoEncrypt, algorithm, key, data, data_size, buffer); |
171 } | 171 } |
172 | 172 |
173 return false; | 173 return false; |
174 } | 174 } |
175 | 175 |
176 bool WebCryptoImpl::DecryptInternal(const WebKit::WebCryptoAlgorithm& algorithm, | 176 bool WebCryptoImpl::DecryptInternal(const blink::WebCryptoAlgorithm& algorithm, |
177 const WebKit::WebCryptoKey& key, | 177 const blink::WebCryptoKey& key, |
178 const unsigned char* data, | 178 const unsigned char* data, |
179 unsigned data_size, | 179 unsigned data_size, |
180 WebKit::WebArrayBuffer* buffer) { | 180 blink::WebArrayBuffer* buffer) { |
181 if (algorithm.id() == WebKit::WebCryptoAlgorithmIdAesCbc) { | 181 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { |
182 return AesCbcEncryptDecrypt( | 182 return AesCbcEncryptDecrypt( |
183 kDoDecrypt, algorithm, key, data, data_size, buffer); | 183 kDoDecrypt, algorithm, key, data, data_size, buffer); |
184 } | 184 } |
185 | 185 |
186 return false; | 186 return false; |
187 } | 187 } |
188 | 188 |
189 bool WebCryptoImpl::DigestInternal(const WebKit::WebCryptoAlgorithm& algorithm, | 189 bool WebCryptoImpl::DigestInternal(const blink::WebCryptoAlgorithm& algorithm, |
190 const unsigned char* data, | 190 const unsigned char* data, |
191 unsigned data_size, | 191 unsigned data_size, |
192 WebKit::WebArrayBuffer* buffer) { | 192 blink::WebArrayBuffer* buffer) { |
193 | 193 |
194 crypto::OpenSSLErrStackTracer(FROM_HERE); | 194 crypto::OpenSSLErrStackTracer(FROM_HERE); |
195 | 195 |
196 const EVP_MD* digest_algorithm; | 196 const EVP_MD* digest_algorithm; |
197 switch (algorithm.id()) { | 197 switch (algorithm.id()) { |
198 case WebKit::WebCryptoAlgorithmIdSha1: | 198 case blink::WebCryptoAlgorithmIdSha1: |
199 digest_algorithm = EVP_sha1(); | 199 digest_algorithm = EVP_sha1(); |
200 break; | 200 break; |
201 case WebKit::WebCryptoAlgorithmIdSha224: | 201 case blink::WebCryptoAlgorithmIdSha224: |
202 digest_algorithm = EVP_sha224(); | 202 digest_algorithm = EVP_sha224(); |
203 break; | 203 break; |
204 case WebKit::WebCryptoAlgorithmIdSha256: | 204 case blink::WebCryptoAlgorithmIdSha256: |
205 digest_algorithm = EVP_sha256(); | 205 digest_algorithm = EVP_sha256(); |
206 break; | 206 break; |
207 case WebKit::WebCryptoAlgorithmIdSha384: | 207 case blink::WebCryptoAlgorithmIdSha384: |
208 digest_algorithm = EVP_sha384(); | 208 digest_algorithm = EVP_sha384(); |
209 break; | 209 break; |
210 case WebKit::WebCryptoAlgorithmIdSha512: | 210 case blink::WebCryptoAlgorithmIdSha512: |
211 digest_algorithm = EVP_sha512(); | 211 digest_algorithm = EVP_sha512(); |
212 break; | 212 break; |
213 default: | 213 default: |
214 // Not a digest algorithm. | 214 // Not a digest algorithm. |
215 return false; | 215 return false; |
216 } | 216 } |
217 | 217 |
218 crypto::ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> digest_context( | 218 crypto::ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> digest_context( |
219 EVP_MD_CTX_create()); | 219 EVP_MD_CTX_create()); |
220 if (!digest_context.get()) { | 220 if (!digest_context.get()) { |
221 return false; | 221 return false; |
222 } | 222 } |
223 | 223 |
224 if (!EVP_DigestInit_ex(digest_context.get(), digest_algorithm, NULL) || | 224 if (!EVP_DigestInit_ex(digest_context.get(), digest_algorithm, NULL) || |
225 !EVP_DigestUpdate(digest_context.get(), data, data_size)) { | 225 !EVP_DigestUpdate(digest_context.get(), data, data_size)) { |
226 return false; | 226 return false; |
227 } | 227 } |
228 | 228 |
229 const int hash_expected_size = EVP_MD_CTX_size(digest_context.get()); | 229 const int hash_expected_size = EVP_MD_CTX_size(digest_context.get()); |
230 if (hash_expected_size <= 0) { | 230 if (hash_expected_size <= 0) { |
231 return false; | 231 return false; |
232 } | 232 } |
233 DCHECK_LE(hash_expected_size, EVP_MAX_MD_SIZE); | 233 DCHECK_LE(hash_expected_size, EVP_MAX_MD_SIZE); |
234 | 234 |
235 *buffer = WebKit::WebArrayBuffer::create(hash_expected_size, 1); | 235 *buffer = blink::WebArrayBuffer::create(hash_expected_size, 1); |
236 unsigned char* const hash_buffer = | 236 unsigned char* const hash_buffer = |
237 reinterpret_cast<unsigned char* const>(buffer->data()); | 237 reinterpret_cast<unsigned char* const>(buffer->data()); |
238 | 238 |
239 unsigned hash_size = 0; | 239 unsigned hash_size = 0; |
240 if (!EVP_DigestFinal_ex(digest_context.get(), hash_buffer, &hash_size) || | 240 if (!EVP_DigestFinal_ex(digest_context.get(), hash_buffer, &hash_size) || |
241 static_cast<int>(hash_size) != hash_expected_size) { | 241 static_cast<int>(hash_size) != hash_expected_size) { |
242 buffer->reset(); | 242 buffer->reset(); |
243 return false; | 243 return false; |
244 } | 244 } |
245 | 245 |
246 return true; | 246 return true; |
247 } | 247 } |
248 | 248 |
249 bool WebCryptoImpl::GenerateKeyInternal( | 249 bool WebCryptoImpl::GenerateKeyInternal( |
250 const WebKit::WebCryptoAlgorithm& algorithm, | 250 const blink::WebCryptoAlgorithm& algorithm, |
251 bool extractable, | 251 bool extractable, |
252 WebKit::WebCryptoKeyUsageMask usage_mask, | 252 blink::WebCryptoKeyUsageMask usage_mask, |
253 WebKit::WebCryptoKey* key) { | 253 blink::WebCryptoKey* key) { |
254 | 254 |
255 unsigned keylen_bytes = 0; | 255 unsigned keylen_bytes = 0; |
256 WebKit::WebCryptoKeyType key_type; | 256 blink::WebCryptoKeyType key_type; |
257 switch (algorithm.id()) { | 257 switch (algorithm.id()) { |
258 case WebKit::WebCryptoAlgorithmIdAesCbc: { | 258 case blink::WebCryptoAlgorithmIdAesCbc: { |
259 const WebKit::WebCryptoAesKeyGenParams* params = | 259 const blink::WebCryptoAesKeyGenParams* params = |
260 algorithm.aesKeyGenParams(); | 260 algorithm.aesKeyGenParams(); |
261 DCHECK(params); | 261 DCHECK(params); |
262 if (params->length() % 8) | 262 if (params->length() % 8) |
263 return false; | 263 return false; |
264 keylen_bytes = params->length() / 8; | 264 keylen_bytes = params->length() / 8; |
265 if (!GetAESCipherByKeyLength(keylen_bytes)) { | 265 if (!GetAESCipherByKeyLength(keylen_bytes)) { |
266 return false; | 266 return false; |
267 } | 267 } |
268 key_type = WebKit::WebCryptoKeyTypeSecret; | 268 key_type = blink::WebCryptoKeyTypeSecret; |
269 break; | 269 break; |
270 } | 270 } |
271 case WebKit::WebCryptoAlgorithmIdHmac: { | 271 case blink::WebCryptoAlgorithmIdHmac: { |
272 const WebKit::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams(); | 272 const blink::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams(); |
273 DCHECK(params); | 273 DCHECK(params); |
274 if (!params->getLength(keylen_bytes)) { | 274 if (!params->getLength(keylen_bytes)) { |
275 keylen_bytes = WebCryptoHmacParamsToBlockSize(params); | 275 keylen_bytes = WebCryptoHmacParamsToBlockSize(params); |
276 } | 276 } |
277 key_type = WebKit::WebCryptoKeyTypeSecret; | 277 key_type = blink::WebCryptoKeyTypeSecret; |
278 break; | 278 break; |
279 } | 279 } |
280 | 280 |
281 default: { return false; } | 281 default: { return false; } |
282 } | 282 } |
283 | 283 |
284 if (keylen_bytes == 0) { | 284 if (keylen_bytes == 0) { |
285 return false; | 285 return false; |
286 } | 286 } |
287 | 287 |
288 crypto::OpenSSLErrStackTracer(FROM_HERE); | 288 crypto::OpenSSLErrStackTracer(FROM_HERE); |
289 | 289 |
290 std::vector<unsigned char> random_bytes(keylen_bytes, 0); | 290 std::vector<unsigned char> random_bytes(keylen_bytes, 0); |
291 if (!(RAND_bytes(&random_bytes[0], keylen_bytes))) { | 291 if (!(RAND_bytes(&random_bytes[0], keylen_bytes))) { |
292 return false; | 292 return false; |
293 } | 293 } |
294 | 294 |
295 *key = WebKit::WebCryptoKey::create( | 295 *key = blink::WebCryptoKey::create( |
296 new SymKeyHandle(&random_bytes[0], random_bytes.size()), | 296 new SymKeyHandle(&random_bytes[0], random_bytes.size()), |
297 key_type, extractable, algorithm, usage_mask); | 297 key_type, extractable, algorithm, usage_mask); |
298 | 298 |
299 return true; | 299 return true; |
300 } | 300 } |
301 | 301 |
302 bool WebCryptoImpl::GenerateKeyPairInternal( | 302 bool WebCryptoImpl::GenerateKeyPairInternal( |
303 const WebKit::WebCryptoAlgorithm& algorithm, | 303 const blink::WebCryptoAlgorithm& algorithm, |
304 bool extractable, | 304 bool extractable, |
305 WebKit::WebCryptoKeyUsageMask usage_mask, | 305 blink::WebCryptoKeyUsageMask usage_mask, |
306 WebKit::WebCryptoKey* public_key, | 306 blink::WebCryptoKey* public_key, |
307 WebKit::WebCryptoKey* private_key) { | 307 blink::WebCryptoKey* private_key) { |
308 // TODO(padolph): Placeholder for OpenSSL implementation. | 308 // TODO(padolph): Placeholder for OpenSSL implementation. |
309 // Issue http://crbug.com/267888. | 309 // Issue http://crbug.com/267888. |
310 return false; | 310 return false; |
311 } | 311 } |
312 | 312 |
313 bool WebCryptoImpl::ImportKeyInternal( | 313 bool WebCryptoImpl::ImportKeyInternal( |
314 WebKit::WebCryptoKeyFormat format, | 314 blink::WebCryptoKeyFormat format, |
315 const unsigned char* key_data, | 315 const unsigned char* key_data, |
316 unsigned key_data_size, | 316 unsigned key_data_size, |
317 const WebKit::WebCryptoAlgorithm& algorithm_or_null, | 317 const blink::WebCryptoAlgorithm& algorithm_or_null, |
318 bool extractable, | 318 bool extractable, |
319 WebKit::WebCryptoKeyUsageMask usage_mask, | 319 blink::WebCryptoKeyUsageMask usage_mask, |
320 WebKit::WebCryptoKey* key) { | 320 blink::WebCryptoKey* key) { |
321 // TODO(eroman): Currently expects algorithm to always be specified, as it is | 321 // TODO(eroman): Currently expects algorithm to always be specified, as it is |
322 // required for raw format. | 322 // required for raw format. |
323 if (algorithm_or_null.isNull()) | 323 if (algorithm_or_null.isNull()) |
324 return false; | 324 return false; |
325 const WebKit::WebCryptoAlgorithm& algorithm = algorithm_or_null; | 325 const blink::WebCryptoAlgorithm& algorithm = algorithm_or_null; |
326 | 326 |
327 // TODO(padolph): Support all relevant alg types and then remove this gate. | 327 // TODO(padolph): Support all relevant alg types and then remove this gate. |
328 if (algorithm.id() != WebKit::WebCryptoAlgorithmIdHmac && | 328 if (algorithm.id() != blink::WebCryptoAlgorithmIdHmac && |
329 algorithm.id() != WebKit::WebCryptoAlgorithmIdAesCbc) { | 329 algorithm.id() != blink::WebCryptoAlgorithmIdAesCbc) { |
330 return false; | 330 return false; |
331 } | 331 } |
332 | 332 |
333 // TODO(padolph): Need to split handling for symmetric (raw or jwk format) and | 333 // TODO(padolph): Need to split handling for symmetric (raw or jwk format) and |
334 // asymmetric (jwk, spki, or pkcs8 format) keys. | 334 // asymmetric (jwk, spki, or pkcs8 format) keys. |
335 // Currently only supporting symmetric. | 335 // Currently only supporting symmetric. |
336 | 336 |
337 // TODO(padolph): jwk handling. Define precedence between jwk contents and | 337 // TODO(padolph): jwk handling. Define precedence between jwk contents and |
338 // this method's parameters, e.g. 'alg' in jwk vs algorithm.id(). Who wins if | 338 // this method's parameters, e.g. 'alg' in jwk vs algorithm.id(). Who wins if |
339 // they differ? (jwk, probably) | 339 // they differ? (jwk, probably) |
340 | 340 |
341 // Symmetric keys are always type secret | 341 // Symmetric keys are always type secret |
342 WebKit::WebCryptoKeyType type = WebKit::WebCryptoKeyTypeSecret; | 342 blink::WebCryptoKeyType type = blink::WebCryptoKeyTypeSecret; |
343 | 343 |
344 const unsigned char* raw_key_data; | 344 const unsigned char* raw_key_data; |
345 unsigned raw_key_data_size; | 345 unsigned raw_key_data_size; |
346 switch (format) { | 346 switch (format) { |
347 case WebKit::WebCryptoKeyFormatRaw: | 347 case blink::WebCryptoKeyFormatRaw: |
348 raw_key_data = key_data; | 348 raw_key_data = key_data; |
349 raw_key_data_size = key_data_size; | 349 raw_key_data_size = key_data_size; |
350 // The NSS implementation fails when importing a raw AES key with a length | 350 // The NSS implementation fails when importing a raw AES key with a length |
351 // incompatible with AES. The line below is to match this behavior. | 351 // incompatible with AES. The line below is to match this behavior. |
352 if (algorithm.id() == WebKit::WebCryptoAlgorithmIdAesCbc && | 352 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc && |
353 !GetAESCipherByKeyLength(raw_key_data_size)) { | 353 !GetAESCipherByKeyLength(raw_key_data_size)) { |
354 return false; | 354 return false; |
355 } | 355 } |
356 break; | 356 break; |
357 case WebKit::WebCryptoKeyFormatJwk: | 357 case blink::WebCryptoKeyFormatJwk: |
358 // TODO(padolph): Handle jwk format; need simple JSON parser. | 358 // TODO(padolph): Handle jwk format; need simple JSON parser. |
359 // break; | 359 // break; |
360 return false; | 360 return false; |
361 default: | 361 default: |
362 return false; | 362 return false; |
363 } | 363 } |
364 | 364 |
365 *key = WebKit::WebCryptoKey::create( | 365 *key = blink::WebCryptoKey::create( |
366 new SymKeyHandle(raw_key_data, raw_key_data_size), | 366 new SymKeyHandle(raw_key_data, raw_key_data_size), |
367 type, extractable, algorithm, usage_mask); | 367 type, extractable, algorithm, usage_mask); |
368 | 368 |
369 return true; | 369 return true; |
370 } | 370 } |
371 | 371 |
372 bool WebCryptoImpl::SignInternal( | 372 bool WebCryptoImpl::SignInternal( |
373 const WebKit::WebCryptoAlgorithm& algorithm, | 373 const blink::WebCryptoAlgorithm& algorithm, |
374 const WebKit::WebCryptoKey& key, | 374 const blink::WebCryptoKey& key, |
375 const unsigned char* data, | 375 const unsigned char* data, |
376 unsigned data_size, | 376 unsigned data_size, |
377 WebKit::WebArrayBuffer* buffer) { | 377 blink::WebArrayBuffer* buffer) { |
378 | 378 |
379 WebKit::WebArrayBuffer result; | 379 blink::WebArrayBuffer result; |
380 | 380 |
381 switch (algorithm.id()) { | 381 switch (algorithm.id()) { |
382 case WebKit::WebCryptoAlgorithmIdHmac: { | 382 case blink::WebCryptoAlgorithmIdHmac: { |
383 | 383 |
384 DCHECK_EQ(key.algorithm().id(), WebKit::WebCryptoAlgorithmIdHmac); | 384 DCHECK_EQ(key.algorithm().id(), blink::WebCryptoAlgorithmIdHmac); |
385 DCHECK_NE(0, key.usages() & WebKit::WebCryptoKeyUsageSign); | 385 DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign); |
386 | 386 |
387 const WebKit::WebCryptoHmacParams* const params = algorithm.hmacParams(); | 387 const blink::WebCryptoHmacParams* const params = algorithm.hmacParams(); |
388 if (!params) | 388 if (!params) |
389 return false; | 389 return false; |
390 | 390 |
391 const EVP_MD* evp_sha = 0; | 391 const EVP_MD* evp_sha = 0; |
392 unsigned int hmac_expected_length = 0; | 392 unsigned int hmac_expected_length = 0; |
393 // Note that HMAC length is determined by the hash used. | 393 // Note that HMAC length is determined by the hash used. |
394 switch (params->hash().id()) { | 394 switch (params->hash().id()) { |
395 case WebKit::WebCryptoAlgorithmIdSha1: | 395 case blink::WebCryptoAlgorithmIdSha1: |
396 evp_sha = EVP_sha1(); | 396 evp_sha = EVP_sha1(); |
397 hmac_expected_length = SHA_DIGEST_LENGTH; | 397 hmac_expected_length = SHA_DIGEST_LENGTH; |
398 break; | 398 break; |
399 case WebKit::WebCryptoAlgorithmIdSha224: | 399 case blink::WebCryptoAlgorithmIdSha224: |
400 evp_sha = EVP_sha224(); | 400 evp_sha = EVP_sha224(); |
401 hmac_expected_length = SHA224_DIGEST_LENGTH; | 401 hmac_expected_length = SHA224_DIGEST_LENGTH; |
402 break; | 402 break; |
403 case WebKit::WebCryptoAlgorithmIdSha256: | 403 case blink::WebCryptoAlgorithmIdSha256: |
404 evp_sha = EVP_sha256(); | 404 evp_sha = EVP_sha256(); |
405 hmac_expected_length = SHA256_DIGEST_LENGTH; | 405 hmac_expected_length = SHA256_DIGEST_LENGTH; |
406 break; | 406 break; |
407 case WebKit::WebCryptoAlgorithmIdSha384: | 407 case blink::WebCryptoAlgorithmIdSha384: |
408 evp_sha = EVP_sha384(); | 408 evp_sha = EVP_sha384(); |
409 hmac_expected_length = SHA384_DIGEST_LENGTH; | 409 hmac_expected_length = SHA384_DIGEST_LENGTH; |
410 break; | 410 break; |
411 case WebKit::WebCryptoAlgorithmIdSha512: | 411 case blink::WebCryptoAlgorithmIdSha512: |
412 evp_sha = EVP_sha512(); | 412 evp_sha = EVP_sha512(); |
413 hmac_expected_length = SHA512_DIGEST_LENGTH; | 413 hmac_expected_length = SHA512_DIGEST_LENGTH; |
414 break; | 414 break; |
415 default: | 415 default: |
416 // Not a digest algorithm. | 416 // Not a digest algorithm. |
417 return false; | 417 return false; |
418 } | 418 } |
419 | 419 |
420 SymKeyHandle* const sym_key = | 420 SymKeyHandle* const sym_key = |
421 reinterpret_cast<SymKeyHandle*>(key.handle()); | 421 reinterpret_cast<SymKeyHandle*>(key.handle()); |
422 const std::vector<unsigned char>& raw_key = sym_key->key(); | 422 const std::vector<unsigned char>& raw_key = sym_key->key(); |
423 | 423 |
424 // OpenSSL wierdness here. | 424 // OpenSSL wierdness here. |
425 // First, HMAC() needs a void* for the key data, so make one up front as a | 425 // First, HMAC() needs a void* for the key data, so make one up front as a |
426 // cosmetic to avoid a cast. Second, OpenSSL does not like a NULL key, | 426 // cosmetic to avoid a cast. Second, OpenSSL does not like a NULL key, |
427 // which will result if the raw_key vector is empty; an entirely valid | 427 // which will result if the raw_key vector is empty; an entirely valid |
428 // case. Handle this specific case by pointing to an empty array. | 428 // case. Handle this specific case by pointing to an empty array. |
429 const unsigned char null_key[] = {}; | 429 const unsigned char null_key[] = {}; |
430 const void* const raw_key_voidp = raw_key.size() ? &raw_key[0] : null_key; | 430 const void* const raw_key_voidp = raw_key.size() ? &raw_key[0] : null_key; |
431 | 431 |
432 result = WebKit::WebArrayBuffer::create(hmac_expected_length, 1); | 432 result = blink::WebArrayBuffer::create(hmac_expected_length, 1); |
433 crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result( | 433 crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result( |
434 reinterpret_cast<unsigned char*>(result.data()), | 434 reinterpret_cast<unsigned char*>(result.data()), |
435 hmac_expected_length); | 435 hmac_expected_length); |
436 | 436 |
437 crypto::OpenSSLErrStackTracer(FROM_HERE); | 437 crypto::OpenSSLErrStackTracer(FROM_HERE); |
438 | 438 |
439 unsigned int hmac_actual_length; | 439 unsigned int hmac_actual_length; |
440 unsigned char* const success = HMAC(evp_sha, | 440 unsigned char* const success = HMAC(evp_sha, |
441 raw_key_voidp, | 441 raw_key_voidp, |
442 raw_key.size(), | 442 raw_key.size(), |
443 data, | 443 data, |
444 data_size, | 444 data_size, |
445 hmac_result.safe_buffer(), | 445 hmac_result.safe_buffer(), |
446 &hmac_actual_length); | 446 &hmac_actual_length); |
447 if (!success || hmac_actual_length != hmac_expected_length) | 447 if (!success || hmac_actual_length != hmac_expected_length) |
448 return false; | 448 return false; |
449 | 449 |
450 break; | 450 break; |
451 } | 451 } |
452 default: | 452 default: |
453 return false; | 453 return false; |
454 } | 454 } |
455 | 455 |
456 *buffer = result; | 456 *buffer = result; |
457 return true; | 457 return true; |
458 } | 458 } |
459 | 459 |
460 bool WebCryptoImpl::VerifySignatureInternal( | 460 bool WebCryptoImpl::VerifySignatureInternal( |
461 const WebKit::WebCryptoAlgorithm& algorithm, | 461 const blink::WebCryptoAlgorithm& algorithm, |
462 const WebKit::WebCryptoKey& key, | 462 const blink::WebCryptoKey& key, |
463 const unsigned char* signature, | 463 const unsigned char* signature, |
464 unsigned signature_size, | 464 unsigned signature_size, |
465 const unsigned char* data, | 465 const unsigned char* data, |
466 unsigned data_size, | 466 unsigned data_size, |
467 bool* signature_match) { | 467 bool* signature_match) { |
468 switch (algorithm.id()) { | 468 switch (algorithm.id()) { |
469 case WebKit::WebCryptoAlgorithmIdHmac: { | 469 case blink::WebCryptoAlgorithmIdHmac: { |
470 WebKit::WebArrayBuffer result; | 470 blink::WebArrayBuffer result; |
471 if (!SignInternal(algorithm, key, data, data_size, &result)) { | 471 if (!SignInternal(algorithm, key, data, data_size, &result)) { |
472 return false; | 472 return false; |
473 } | 473 } |
474 | 474 |
475 // Handling of truncated signatures is underspecified in the WebCrypto | 475 // Handling of truncated signatures is underspecified in the WebCrypto |
476 // spec, so here we fail verification if a truncated signature is being | 476 // spec, so here we fail verification if a truncated signature is being |
477 // verified. | 477 // verified. |
478 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 | 478 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 |
479 *signature_match = | 479 *signature_match = |
480 result.byteLength() == signature_size && | 480 result.byteLength() == signature_size && |
481 crypto::SecureMemEqual(result.data(), signature, signature_size); | 481 crypto::SecureMemEqual(result.data(), signature, signature_size); |
482 | 482 |
483 break; | 483 break; |
484 } | 484 } |
485 default: | 485 default: |
486 return false; | 486 return false; |
487 } | 487 } |
488 return true; | 488 return true; |
489 } | 489 } |
490 | 490 |
491 } // namespace content | 491 } // namespace content |
OLD | NEW |