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

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

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

Powered by Google App Engine
This is Rietveld 408576698