Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(977)

Side by Side Diff: content/renderer/webcrypto/platform_crypto_openssl.cc

Issue 188203003: Move webcrypto to child/ and add support to worker_webkitplatformsupport. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixes to gypis Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/renderer/webcrypto/platform_crypto.h"
6
7 #include <vector>
8 #include <openssl/aes.h>
9 #include <openssl/evp.h>
10 #include <openssl/hmac.h>
11 #include <openssl/rand.h>
12 #include <openssl/sha.h>
13
14 #include "base/logging.h"
15 #include "content/renderer/webcrypto/crypto_data.h"
16 #include "content/renderer/webcrypto/webcrypto_util.h"
17 #include "crypto/openssl_util.h"
18 #include "third_party/WebKit/public/platform/WebArrayBuffer.h"
19 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
21 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
22
23 namespace content {
24
25 namespace webcrypto {
26
27 namespace platform {
28
29 class SymKey : public Key {
30 public:
31 explicit SymKey(const CryptoData& key_data)
32 : key_(key_data.bytes(), key_data.bytes() + key_data.byte_length()) {}
33
34 virtual SymKey* AsSymKey() OVERRIDE { return this; }
35 virtual PublicKey* AsPublicKey() OVERRIDE { return NULL; }
36 virtual PrivateKey* AsPrivateKey() OVERRIDE { return NULL; }
37
38 const std::vector<unsigned char>& key() const { return key_; }
39
40 private:
41 const std::vector<unsigned char> key_;
42
43 DISALLOW_COPY_AND_ASSIGN(SymKey);
44 };
45
46 namespace {
47
48 const EVP_CIPHER* GetAESCipherByKeyLength(unsigned int key_length_bytes) {
49 // OpenSSL supports AES CBC ciphers for only 3 key lengths: 128, 192, 256 bits
50 switch (key_length_bytes) {
51 case 16:
52 return EVP_aes_128_cbc();
53 case 24:
54 return EVP_aes_192_cbc();
55 case 32:
56 return EVP_aes_256_cbc();
57 default:
58 return NULL;
59 }
60 }
61
62 const EVP_MD* GetDigest(blink::WebCryptoAlgorithmId id) {
63 switch (id) {
64 case blink::WebCryptoAlgorithmIdSha1:
65 return EVP_sha1();
66 case blink::WebCryptoAlgorithmIdSha224:
67 return EVP_sha224();
68 case blink::WebCryptoAlgorithmIdSha256:
69 return EVP_sha256();
70 case blink::WebCryptoAlgorithmIdSha384:
71 return EVP_sha384();
72 case blink::WebCryptoAlgorithmIdSha512:
73 return EVP_sha512();
74 default:
75 return NULL;
76 }
77 }
78
79 // OpenSSL constants for EVP_CipherInit_ex(), do not change
80 enum CipherOperation { kDoDecrypt = 0, kDoEncrypt = 1 };
81
82 Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode,
83 SymKey* key,
84 const CryptoData& iv,
85 const CryptoData& data,
86 blink::WebArrayBuffer* buffer) {
87 CipherOperation cipher_operation =
88 (mode == ENCRYPT) ? kDoEncrypt : kDoDecrypt;
89
90 if (data.byte_length() >= INT_MAX - AES_BLOCK_SIZE) {
91 // TODO(padolph): Handle this by chunking the input fed into OpenSSL. Right
92 // now it doesn't make much difference since the one-shot API would end up
93 // blowing out the memory and crashing anyway.
94 return Status::ErrorDataTooLarge();
95 }
96
97 // Note: PKCS padding is enabled by default
98 crypto::ScopedOpenSSL<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free> context(
99 EVP_CIPHER_CTX_new());
100
101 if (!context.get())
102 return Status::Error();
103
104 const EVP_CIPHER* const cipher = GetAESCipherByKeyLength(key->key().size());
105 DCHECK(cipher);
106
107 if (!EVP_CipherInit_ex(context.get(),
108 cipher,
109 NULL,
110 &key->key()[0],
111 iv.bytes(),
112 cipher_operation)) {
113 return Status::Error();
114 }
115
116 // According to the openssl docs, the amount of data written may be as large
117 // as (data_size + cipher_block_size - 1), constrained to a multiple of
118 // cipher_block_size.
119 unsigned int output_max_len = data.byte_length() + AES_BLOCK_SIZE - 1;
120 const unsigned remainder = output_max_len % AES_BLOCK_SIZE;
121 if (remainder != 0)
122 output_max_len += AES_BLOCK_SIZE - remainder;
123 DCHECK_GT(output_max_len, data.byte_length());
124
125 *buffer = blink::WebArrayBuffer::create(output_max_len, 1);
126
127 unsigned char* const buffer_data =
128 reinterpret_cast<unsigned char*>(buffer->data());
129
130 int output_len = 0;
131 if (!EVP_CipherUpdate(context.get(),
132 buffer_data,
133 &output_len,
134 data.bytes(),
135 data.byte_length()))
136 return Status::Error();
137 int final_output_chunk_len = 0;
138 if (!EVP_CipherFinal_ex(
139 context.get(), buffer_data + output_len, &final_output_chunk_len)) {
140 return Status::Error();
141 }
142
143 const unsigned int final_output_len =
144 static_cast<unsigned int>(output_len) +
145 static_cast<unsigned int>(final_output_chunk_len);
146 DCHECK_LE(final_output_len, output_max_len);
147
148 ShrinkBuffer(buffer, final_output_len);
149
150 return Status::Success();
151 }
152
153 } // namespace
154
155 Status ExportKeyRaw(SymKey* key, blink::WebArrayBuffer* buffer) {
156 *buffer = CreateArrayBuffer(Uint8VectorStart(key->key()), key->key().size());
157 return Status::Success();
158 }
159
160 void Init() { crypto::EnsureOpenSSLInit(); }
161
162 Status EncryptDecryptAesCbc(EncryptOrDecrypt mode,
163 SymKey* key,
164 const CryptoData& data,
165 const CryptoData& iv,
166 blink::WebArrayBuffer* buffer) {
167 // TODO(eroman): inline the function here.
168 return AesCbcEncryptDecrypt(mode, key, iv, data, buffer);
169 }
170
171 Status DigestSha(blink::WebCryptoAlgorithmId algorithm,
172 const CryptoData& data,
173 blink::WebArrayBuffer* buffer) {
174 crypto::OpenSSLErrStackTracer(FROM_HERE);
175
176 const EVP_MD* digest_algorithm = GetDigest(algorithm);
177 if (!digest_algorithm)
178 return Status::ErrorUnexpected();
179
180 crypto::ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> digest_context(
181 EVP_MD_CTX_create());
182 if (!digest_context.get())
183 return Status::Error();
184
185 if (!EVP_DigestInit_ex(digest_context.get(), digest_algorithm, NULL) ||
186 !EVP_DigestUpdate(
187 digest_context.get(), data.bytes(), data.byte_length())) {
188 return Status::Error();
189 }
190
191 const int hash_expected_size = EVP_MD_CTX_size(digest_context.get());
192 if (hash_expected_size <= 0)
193 return Status::ErrorUnexpected();
194 DCHECK_LE(hash_expected_size, EVP_MAX_MD_SIZE);
195
196 *buffer = blink::WebArrayBuffer::create(hash_expected_size, 1);
197 unsigned char* const hash_buffer =
198 reinterpret_cast<unsigned char* const>(buffer->data());
199
200 unsigned int hash_size = 0;
201 if (!EVP_DigestFinal_ex(digest_context.get(), hash_buffer, &hash_size) ||
202 static_cast<int>(hash_size) != hash_expected_size) {
203 buffer->reset();
204 return Status::Error();
205 }
206
207 return Status::Success();
208 }
209
210 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
211 bool extractable,
212 blink::WebCryptoKeyUsageMask usage_mask,
213 unsigned keylen_bytes,
214 blink::WebCryptoKey* key) {
215 // TODO(eroman): Is this right?
216 if (keylen_bytes == 0)
217 return Status::ErrorGenerateKeyLength();
218
219 crypto::OpenSSLErrStackTracer(FROM_HERE);
220
221 std::vector<unsigned char> random_bytes(keylen_bytes, 0);
222 if (!(RAND_bytes(&random_bytes[0], keylen_bytes)))
223 return Status::Error();
224
225 blink::WebCryptoKeyAlgorithm key_algorithm;
226 if (!CreateSecretKeyAlgorithm(algorithm, keylen_bytes, &key_algorithm))
227 return Status::ErrorUnexpected();
228
229 *key = blink::WebCryptoKey::create(new SymKey(CryptoData(random_bytes)),
230 blink::WebCryptoKeyTypeSecret,
231 extractable,
232 key_algorithm,
233 usage_mask);
234
235 return Status::Success();
236 }
237
238 Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm,
239 bool extractable,
240 blink::WebCryptoKeyUsageMask usage_mask,
241 unsigned int modulus_length_bits,
242 const CryptoData& public_exponent,
243 const blink::WebCryptoAlgorithm& hash,
244 blink::WebCryptoKey* public_key,
245 blink::WebCryptoKey* private_key) {
246 // TODO(padolph): Placeholder for OpenSSL implementation.
247 // Issue http://crbug.com/267888.
248 return Status::ErrorUnsupported();
249 }
250
251 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm,
252 const CryptoData& key_data,
253 bool extractable,
254 blink::WebCryptoKeyUsageMask usage_mask,
255 blink::WebCryptoKey* key) {
256
257 blink::WebCryptoKeyAlgorithm key_algorithm;
258 if (!CreateSecretKeyAlgorithm(
259 algorithm, key_data.byte_length(), &key_algorithm))
260 return Status::ErrorUnexpected();
261
262 *key = blink::WebCryptoKey::create(new SymKey(key_data),
263 blink::WebCryptoKeyTypeSecret,
264 extractable,
265 key_algorithm,
266 usage_mask);
267
268 return Status::Success();
269 }
270
271 Status SignHmac(SymKey* key,
272 const blink::WebCryptoAlgorithm& hash,
273 const CryptoData& data,
274 blink::WebArrayBuffer* buffer) {
275 blink::WebArrayBuffer result;
276
277 const EVP_MD* digest_algorithm = GetDigest(hash.id());
278 if (!digest_algorithm)
279 return Status::ErrorUnsupported();
280 unsigned int hmac_expected_length = EVP_MD_size(digest_algorithm);
281
282 const std::vector<unsigned char>& raw_key = key->key();
283
284 // OpenSSL wierdness here.
285 // First, HMAC() needs a void* for the key data, so make one up front as a
286 // cosmetic to avoid a cast. Second, OpenSSL does not like a NULL key,
287 // which will result if the raw_key vector is empty; an entirely valid
288 // case. Handle this specific case by pointing to an empty array.
289 const unsigned char null_key[] = {};
290 const void* const raw_key_voidp = raw_key.size() ? &raw_key[0] : null_key;
291
292 result = blink::WebArrayBuffer::create(hmac_expected_length, 1);
293 crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result(
294 reinterpret_cast<unsigned char*>(result.data()), hmac_expected_length);
295
296 crypto::OpenSSLErrStackTracer(FROM_HERE);
297
298 unsigned int hmac_actual_length;
299 unsigned char* const success = HMAC(digest_algorithm,
300 raw_key_voidp,
301 raw_key.size(),
302 data.bytes(),
303 data.byte_length(),
304 hmac_result.safe_buffer(),
305 &hmac_actual_length);
306 if (!success || hmac_actual_length != hmac_expected_length)
307 return Status::Error();
308
309 *buffer = result;
310 return Status::Success();
311 }
312
313 Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
314 bool extractable,
315 blink::WebCryptoKeyUsageMask usage_mask,
316 const CryptoData& modulus_data,
317 const CryptoData& exponent_data,
318 blink::WebCryptoKey* key) {
319 // TODO(padolph): Placeholder for OpenSSL implementation.
320 // Issue
321 return Status::ErrorUnsupported();
322 }
323
324 Status EncryptDecryptAesGcm(EncryptOrDecrypt mode,
325 SymKey* key,
326 const CryptoData& data,
327 const CryptoData& iv,
328 const CryptoData& additional_data,
329 unsigned int tag_length_bits,
330 blink::WebArrayBuffer* buffer) {
331 // TODO(eroman): http://crbug.com/267888
332 return Status::ErrorUnsupported();
333 }
334
335 // Guaranteed that key is valid.
336 Status EncryptRsaEsPkcs1v1_5(PublicKey* key,
337 const CryptoData& data,
338 blink::WebArrayBuffer* buffer) {
339 // TODO(eroman): http://crbug.com/267888
340 return Status::ErrorUnsupported();
341 }
342
343 Status DecryptRsaEsPkcs1v1_5(PrivateKey* key,
344 const CryptoData& data,
345 blink::WebArrayBuffer* buffer) {
346 // TODO(eroman): http://crbug.com/267888
347 return Status::ErrorUnsupported();
348 }
349
350 Status SignRsaSsaPkcs1v1_5(PrivateKey* key,
351 const blink::WebCryptoAlgorithm& hash,
352 const CryptoData& data,
353 blink::WebArrayBuffer* buffer) {
354 // TODO(eroman): http://crbug.com/267888
355 return Status::ErrorUnsupported();
356 }
357
358 // Key is guaranteed to be an RSA SSA key.
359 Status VerifyRsaSsaPkcs1v1_5(PublicKey* key,
360 const blink::WebCryptoAlgorithm& hash,
361 const CryptoData& signature,
362 const CryptoData& data,
363 bool* signature_match) {
364 // TODO(eroman): http://crbug.com/267888
365 return Status::ErrorUnsupported();
366 }
367
368 Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm_or_null,
369 const CryptoData& key_data,
370 bool extractable,
371 blink::WebCryptoKeyUsageMask usage_mask,
372 blink::WebCryptoKey* key) {
373 // TODO(eroman): http://crbug.com/267888
374 return Status::ErrorUnsupported();
375 }
376
377 Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm_or_null,
378 const CryptoData& key_data,
379 bool extractable,
380 blink::WebCryptoKeyUsageMask usage_mask,
381 blink::WebCryptoKey* key) {
382 // TODO(eroman): http://crbug.com/267888
383 return Status::ErrorUnsupported();
384 }
385
386 Status ExportKeySpki(PublicKey* key, blink::WebArrayBuffer* buffer) {
387 // TODO(eroman): http://crbug.com/267888
388 return Status::ErrorUnsupported();
389 }
390
391 } // namespace platform
392
393 } // namespace webcrypto
394
395 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/webcrypto/platform_crypto_nss.cc ('k') | content/renderer/webcrypto/shared_crypto.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698