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

Side by Side Diff: Source/modules/crypto/NormalizeAlgorithm.cpp

Issue 22992006: WebCrypto: Add exception messages for algorithm normalization failures. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Add a comment to explain inline size of Vector Created 7 years, 4 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
« no previous file with comments | « LayoutTests/crypto/sign-verify-expected.txt ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved. 2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 23 matching lines...) Expand all
34 #include "bindings/v8/Dictionary.h" 34 #include "bindings/v8/Dictionary.h"
35 #include "bindings/v8/ExceptionState.h" 35 #include "bindings/v8/ExceptionState.h"
36 #include "core/dom/ExceptionCode.h" 36 #include "core/dom/ExceptionCode.h"
37 #include "public/platform/WebCryptoAlgorithm.h" 37 #include "public/platform/WebCryptoAlgorithm.h"
38 #include "public/platform/WebCryptoAlgorithmParams.h" 38 #include "public/platform/WebCryptoAlgorithmParams.h"
39 #include "wtf/ArrayBuffer.h" 39 #include "wtf/ArrayBuffer.h"
40 #include "wtf/ArrayBufferView.h" 40 #include "wtf/ArrayBufferView.h"
41 #include "wtf/HashMap.h" 41 #include "wtf/HashMap.h"
42 #include "wtf/Uint8Array.h" 42 #include "wtf/Uint8Array.h"
43 #include "wtf/Vector.h" 43 #include "wtf/Vector.h"
44 #include "wtf/text/StringBuilder.h"
44 #include "wtf/text/StringHash.h" 45 #include "wtf/text/StringHash.h"
45 46
46 namespace WebCore { 47 namespace WebCore {
47 48
48 namespace { 49 namespace {
49 50
50 struct AlgorithmNameMapping { 51 struct AlgorithmNameMapping {
51 const char* const algorithmName; 52 const char* const algorithmName;
52 WebKit::WebCryptoAlgorithmId algorithmId; 53 WebKit::WebCryptoAlgorithmId algorithmId;
53 }; 54 };
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 m_algorithms[mapping.algorithmId].algorithmName = mapping.algorithmName; 154 m_algorithms[mapping.algorithmId].algorithmName = mapping.algorithmName;
154 m_algorithms[mapping.algorithmId].algorithmId = mapping.algorithmId; 155 m_algorithms[mapping.algorithmId].algorithmId = mapping.algorithmId;
155 } 156 }
156 157
157 for (size_t i = 0; i < WTF_ARRAY_LENGTH(operationParamsMappings); ++i) { 158 for (size_t i = 0; i < WTF_ARRAY_LENGTH(operationParamsMappings); ++i) {
158 const OperationParamsMapping& mapping = operationParamsMappings[i]; 159 const OperationParamsMapping& mapping = operationParamsMappings[i];
159 m_algorithms[mapping.algorithmId].paramsForOperation[mapping.operation] = mapping.params; 160 m_algorithms[mapping.algorithmId].paramsForOperation[mapping.operation] = mapping.params;
160 } 161 }
161 } 162 }
162 163
163 PassOwnPtr<WebKit::WebCryptoAlgorithmParams> parseAesCbcParams(const Dictionary& raw) 164 // ExceptionContext holds a stack of string literals which describe what was
165 // happening at the time the exception was thrown. This is helpful because
166 // parsing of the algorithm dictionary can be recursive and it is difficult to
167 // tell what went wrong from the exception type alone (TypeError).
168 class ExceptionContext {
169 public:
170 void add(const char* message)
171 {
172 m_messages.append(message);
173 }
174
175 // Join all of the string literals into a single String.
176 String toString() const
177 {
178 if (m_messages.isEmpty())
179 return String();
180
181 StringBuilder result;
182 const char* Separator = ": ";
183
184 // Reserve the string length to avoid reallocations.
abarth-chromium 2013/08/21 19:17:12 I'd remove this "what" comment.
185 size_t length = (m_messages.size() - 1) * strlen(Separator);
186 for (size_t i = 0; i < m_messages.size(); ++i)
187 length += strlen(m_messages[i]);
188 result.reserveCapacity(length);
189
190 // Join the strings with Separator.
abarth-chromium 2013/08/21 19:17:12 this one too
191 for (size_t i = 0; i < m_messages.size(); ++i) {
192 if (i)
193 result.append(Separator, strlen(Separator));
194 result.append(m_messages[i], strlen(m_messages[i]));
195 }
196
197 return result.toString();
198 }
199
200 String toString(const char* message) const
201 {
202 ExceptionContext stack(*this);
203 stack.add(message);
204 return stack.toString();
205 }
206
207 String toString(const char* message1, const char* message2) const
208 {
209 ExceptionContext stack(*this);
210 stack.add(message1);
211 stack.add(message2);
212 return stack.toString();
213 }
214
215 private:
216 // This inline size is large enough to avoid having to grow the Vector in
217 // the majority of cases (up to 1 nested algorithm identifier).
218 Vector<const char*, 10> m_messages;
219 };
220
221 bool getArrayBufferView(const Dictionary& raw, const char* propertyName, RefPtr< ArrayBufferView>& buffer, const ExceptionContext& context, ExceptionState& es)
222 {
223 if (!raw.get(propertyName, buffer) || !buffer) {
224 es.throwTypeError(context.toString(propertyName, "Missing or not a Array BufferView"));
225 return false;
226 }
227 return true;
228 }
229
230 bool getUint8Array(const Dictionary& raw, const char* propertyName, RefPtr<Uint8 Array>& array, const ExceptionContext& context, ExceptionState& es)
231 {
232 if (!raw.get(propertyName, array) || !array) {
233 es.throwTypeError(context.toString(propertyName, "Missing or not a Uint8 Array"));
234 return false;
235 }
236 return true;
237 }
238
239 bool getInteger(const Dictionary& raw, const char* propertyName, double& value, double minValue, double maxValue, const ExceptionContext& context, ExceptionStat e& es)
240 {
241 double number;
242 if (!raw.get(propertyName, number)) {
243 es.throwTypeError(context.toString(propertyName, "Missing or not a numbe r"));
244 return false;
245 }
246
247 if (number == INFINITY || number == -INFINITY || number == NAN) {
248 es.throwTypeError(context.toString(propertyName, "Outside of numeric ran ge"));
249 return false;
250 }
251
252 // Convert to an integer according to WebIDL's [EnforceRange].
253 double integer = floor(abs(number));
254 if (number < 0)
255 integer = -integer;
256
257 if (integer < minValue || integer > maxValue) {
258 es.throwTypeError(context.toString(propertyName, "Outside of numeric ran ge"));
259 return false;
260 }
261
262 value = integer;
263 return true;
264 }
265
266 bool getOptionalInteger(const Dictionary& raw, const char* propertyName, bool& h asValue, double& value, double minValue, double maxValue, const ExceptionContext & context, ExceptionState& es)
267 {
268 double number;
269 if (!raw.get(propertyName, number)) {
270 // FIXME: If the property exists but is NOT a number, should fail.
271 hasValue = false;
272 return true;
273 }
274
275 hasValue = true;
276 return getInteger(raw, propertyName, value, minValue, maxValue, context, es) ;
277 }
278
279 bool getUint32(const Dictionary& raw, const char* propertyName, uint32_t& value, const ExceptionContext& context, ExceptionState& es)
280 {
281 double number;
282 if (!getInteger(raw, propertyName, number, 0, 0xFFFFFFFF, context, es))
283 return false;
284 value = number;
285 return true;
286 }
287
288 bool getUint16(const Dictionary& raw, const char* propertyName, uint16_t& value, const ExceptionContext& context, ExceptionState& es)
289 {
290 double number;
291 if (!getInteger(raw, propertyName, number, 0, 0xFFFF, context, es))
292 return false;
293 value = number;
294 return true;
295 }
296
297 bool getOptionalUint32(const Dictionary& raw, const char* propertyName, bool& ha sValue, uint32_t& value, const ExceptionContext& context, ExceptionState& es)
298 {
299 double number;
300 if (!getOptionalInteger(raw, propertyName, hasValue, number, 0, 0xFFFFFFFF, context, es))
301 return false;
302 if (hasValue)
303 value = number;
304 return true;
305 }
306
307 bool parseAesCbcParams(const Dictionary& raw, OwnPtr<WebKit::WebCryptoAlgorithmP arams>& params, const ExceptionContext& context, ExceptionState& es)
164 { 308 {
165 RefPtr<ArrayBufferView> iv; 309 RefPtr<ArrayBufferView> iv;
166 if (!raw.get("iv", iv) || !iv) 310 if (!getArrayBufferView(raw, "iv", iv, context, es))
167 return nullptr; 311 return false;
168 312
169 if (iv->byteLength() != 16) 313 if (iv->byteLength() != 16) {
170 return nullptr; 314 es.throwTypeError(context.toString("iv", "Must be 16 bytes"));
171 315 return false;
172 return adoptPtr(new WebKit::WebCryptoAesCbcParams(static_cast<unsigned char* >(iv->baseAddress()), iv->byteLength())); 316 }
173 } 317
174 318 params = adoptPtr(new WebKit::WebCryptoAesCbcParams(static_cast<unsigned cha r*>(iv->baseAddress()), iv->byteLength()));
175 PassOwnPtr<WebKit::WebCryptoAlgorithmParams> parseAesKeyGenParams(const Dictiona ry& raw) 319 return true;
176 { 320 }
177 int32_t length; 321
178 if (!raw.get("length", length)) 322 bool parseAesKeyGenParams(const Dictionary& raw, OwnPtr<WebKit::WebCryptoAlgorit hmParams>& params, const ExceptionContext& context, ExceptionState& es)
179 return nullptr; 323 {
180 if (length < 0 || length > 0xFFFF) 324 uint16_t length;
181 return nullptr; 325 if (!getUint16(raw, "length", length, context, es))
182 return adoptPtr(new WebKit::WebCryptoAesKeyGenParams(length)); 326 return false;
183 } 327
184 328 params = adoptPtr(new WebKit::WebCryptoAesKeyGenParams(length));
185 bool parseHash(const Dictionary& raw, WebKit::WebCryptoAlgorithm& hash) 329 return true;
330 }
331
332 bool normalizeAlgorithm(const Dictionary&, AlgorithmOperation, WebKit::WebCrypto Algorithm&, ExceptionContext, ExceptionState&);
333
334 bool parseHash(const Dictionary& raw, WebKit::WebCryptoAlgorithm& hash, Exceptio nContext context, ExceptionState& es)
186 { 335 {
187 Dictionary rawHash; 336 Dictionary rawHash;
188 if (!raw.get("hash", rawHash)) 337 if (!raw.get("hash", rawHash)) {
189 return false; 338 es.throwTypeError(context.toString("hash", "Missing or not a dictionary" ));
190 339 return false;
191 TrackExceptionState es; 340 }
192 return normalizeAlgorithm(rawHash, Digest, hash, es); 341
193 } 342 context.add("hash");
194 343 return normalizeAlgorithm(rawHash, Digest, hash, context, es);
195 PassOwnPtr<WebKit::WebCryptoAlgorithmParams> parseHmacParams(const Dictionary& r aw) 344 }
345
346 bool parseHmacParams(const Dictionary& raw, OwnPtr<WebKit::WebCryptoAlgorithmPar ams>& params, const ExceptionContext& context, ExceptionState& es)
196 { 347 {
197 WebKit::WebCryptoAlgorithm hash; 348 WebKit::WebCryptoAlgorithm hash;
198 if (!parseHash(raw, hash)) 349 if (!parseHash(raw, hash, context, es))
199 return nullptr; 350 return false;
200 return adoptPtr(new WebKit::WebCryptoHmacParams(hash)); 351
201 } 352 params = adoptPtr(new WebKit::WebCryptoHmacParams(hash));
202 353 return true;
203 PassOwnPtr<WebKit::WebCryptoAlgorithmParams> parseHmacKeyParams(const Dictionary & raw) 354 }
355
356 bool parseHmacKeyParams(const Dictionary& raw, OwnPtr<WebKit::WebCryptoAlgorithm Params>& params, const ExceptionContext& context, ExceptionState& es)
204 { 357 {
205 WebKit::WebCryptoAlgorithm hash; 358 WebKit::WebCryptoAlgorithm hash;
206 if (!parseHash(raw, hash)) 359 if (!parseHash(raw, hash, context, es))
207 return nullptr; 360 return false;
208 361
209 // FIXME: Should fail if length was specified but of the wrong type. 362 bool hasLength;
210 bool hasLength = false; 363 uint32_t length;
211 int32_t length = 0; 364 if (!getOptionalUint32(raw, "length", hasLength, length, context, es))
212 if (raw.get("length", length)) { 365 return false;
213 hasLength = true; 366
214 if (length < 0) 367 params = adoptPtr(new WebKit::WebCryptoHmacKeyParams(hash, hasLength, length ));
215 return nullptr; 368 return true;
216 } 369 }
217 370
218 return adoptPtr(new WebKit::WebCryptoHmacKeyParams(hash, hasLength, length)) ; 371 bool parseRsaSsaParams(const Dictionary& raw, OwnPtr<WebKit::WebCryptoAlgorithmP arams>& params, const ExceptionContext& context, ExceptionState& es)
219 }
220
221 PassOwnPtr<WebKit::WebCryptoAlgorithmParams> parseRsaSsaParams(const Dictionary& raw)
222 { 372 {
223 WebKit::WebCryptoAlgorithm hash; 373 WebKit::WebCryptoAlgorithm hash;
224 if (!parseHash(raw, hash)) 374 if (!parseHash(raw, hash, context, es))
225 return nullptr; 375 return false;
226 return adoptPtr(new WebKit::WebCryptoRsaSsaParams(hash)); 376
227 } 377 params = adoptPtr(new WebKit::WebCryptoRsaSsaParams(hash));
228 378 return true;
229 PassOwnPtr<WebKit::WebCryptoAlgorithmParams> parseRsaKeyGenParams(const Dictiona ry& raw) 379 }
230 { 380
231 // FIXME: This is losing precision; modulusLength is supposed to be a uint32 381 bool parseRsaKeyGenParams(const Dictionary& raw, OwnPtr<WebKit::WebCryptoAlgorit hmParams>& params, const ExceptionContext& context, ExceptionState& es)
232 int32_t modulusLength; 382 {
233 if (!raw.get("modulusLength", modulusLength)) 383 uint32_t modulusLength;
234 return nullptr; 384 if (!getUint32(raw, "modulusLength", modulusLength, context, es))
235 if (modulusLength < 0) 385 return false;
236 return nullptr;
237 386
238 RefPtr<Uint8Array> publicExponent; 387 RefPtr<Uint8Array> publicExponent;
239 if (!raw.get("publicExponent", publicExponent) || !publicExponent) 388 if (!getUint8Array(raw, "publicExponent", publicExponent, context, es))
240 return nullptr; 389 return false;
241 return adoptPtr(new WebKit::WebCryptoRsaKeyGenParams(modulusLength, static_c ast<const unsigned char*>(publicExponent->baseAddress()), publicExponent->byteLe ngth())); 390
242 } 391 params = adoptPtr(new WebKit::WebCryptoRsaKeyGenParams(modulusLength, static _cast<const unsigned char*>(publicExponent->baseAddress()), publicExponent->byte Length()));
243 392 return true;
244 PassOwnPtr<WebKit::WebCryptoAlgorithmParams> parseAlgorithmParams(const Dictiona ry& raw, WebKit::WebCryptoAlgorithmParamsType type) 393 }
394
395 bool parseAlgorithmParams(const Dictionary& raw, WebKit::WebCryptoAlgorithmParam sType type, OwnPtr<WebKit::WebCryptoAlgorithmParams>& params, ExceptionContext& context, ExceptionState& es)
245 { 396 {
246 switch (type) { 397 switch (type) {
247 case WebKit::WebCryptoAlgorithmParamsTypeNone: 398 case WebKit::WebCryptoAlgorithmParamsTypeNone:
248 return nullptr; 399 return true;
249 case WebKit::WebCryptoAlgorithmParamsTypeAesCbcParams: 400 case WebKit::WebCryptoAlgorithmParamsTypeAesCbcParams:
250 return parseAesCbcParams(raw); 401 context.add("AesCbcParams");
402 return parseAesCbcParams(raw, params, context, es);
251 case WebKit::WebCryptoAlgorithmParamsTypeAesKeyGenParams: 403 case WebKit::WebCryptoAlgorithmParamsTypeAesKeyGenParams:
252 return parseAesKeyGenParams(raw); 404 context.add("AesKeyGenParams");
405 return parseAesKeyGenParams(raw, params, context, es);
253 case WebKit::WebCryptoAlgorithmParamsTypeHmacParams: 406 case WebKit::WebCryptoAlgorithmParamsTypeHmacParams:
254 return parseHmacParams(raw); 407 context.add("HmacParams");
408 return parseHmacParams(raw, params, context, es);
255 case WebKit::WebCryptoAlgorithmParamsTypeHmacKeyParams: 409 case WebKit::WebCryptoAlgorithmParamsTypeHmacKeyParams:
256 return parseHmacKeyParams(raw); 410 context.add("HmacKeyParams");
411 return parseHmacKeyParams(raw, params, context, es);
257 case WebKit::WebCryptoAlgorithmParamsTypeRsaSsaParams: 412 case WebKit::WebCryptoAlgorithmParamsTypeRsaSsaParams:
258 return parseRsaSsaParams(raw); 413 context.add("RsaSSaParams");
414 return parseRsaSsaParams(raw, params, context, es);
259 case WebKit::WebCryptoAlgorithmParamsTypeRsaKeyGenParams: 415 case WebKit::WebCryptoAlgorithmParamsTypeRsaKeyGenParams:
260 return parseRsaKeyGenParams(raw); 416 context.add("RsaKeyGenParams");
417 return parseRsaKeyGenParams(raw, params, context, es);
261 } 418 }
262 ASSERT_NOT_REACHED(); 419 ASSERT_NOT_REACHED();
263 return nullptr; 420 return false;
264 } 421 }
265 422
266 const AlgorithmInfo* algorithmInfo(const Dictionary& raw, ExceptionState& es) 423 const AlgorithmInfo* algorithmInfo(const Dictionary& raw, const ExceptionContext & context, ExceptionState& es)
267 { 424 {
425 if (!raw.isObject()) {
426 es.throwTypeError(context.toString("Not an object"));
427 return 0;
428 }
429
268 String algorithmName; 430 String algorithmName;
269 if (!raw.get("name", algorithmName)) { 431 if (!raw.get("name", algorithmName)) {
270 es.throwDOMException(NotSupportedError); 432 es.throwTypeError(context.toString("name", "Missing or not a string"));
271 return 0;
272 }
273
274 if (!algorithmName.containsOnlyASCII()) {
275 es.throwDOMException(SyntaxError);
276 return 0; 433 return 0;
277 } 434 }
278 435
279 const AlgorithmInfo* info = AlgorithmRegistry::lookupAlgorithmByName(algorit hmName); 436 const AlgorithmInfo* info = AlgorithmRegistry::lookupAlgorithmByName(algorit hmName);
280 if (!info) { 437 if (!info) {
281 es.throwDOMException(NotSupportedError); 438 es.throwDOMException(NotSupportedError, context.toString("Unrecognized a lgorithm name"));
282 return 0; 439 return 0;
283 } 440 }
284 441
285 return info; 442 return info;
286 } 443 }
287 444
288 } // namespace
289
290 // FIXME: Throw the correct exception types!
291 // This implementation corresponds with: 445 // This implementation corresponds with:
292 // http://www.w3.org/TR/WebCryptoAPI/#algorithm-normalizing-rules 446 // http://www.w3.org/TR/WebCryptoAPI/#algorithm-normalizing-rules
447 bool normalizeAlgorithm(const Dictionary& raw, AlgorithmOperation op, WebKit::We bCryptoAlgorithm& algorithm, ExceptionContext context, ExceptionState& es)
448 {
449 context.add("Algorithm");
450
451 const AlgorithmInfo* info = algorithmInfo(raw, context, es);
452 if (!info)
453 return false;
454
455 context.add(info->algorithmName);
456
457 if (info->paramsForOperation[op] == UnsupportedOp) {
458 es.throwDOMException(NotSupportedError, context.toString("Unsupported op eration"));
459 return false;
460 }
461
462 WebKit::WebCryptoAlgorithmParamsType paramsType = static_cast<WebKit::WebCry ptoAlgorithmParamsType>(info->paramsForOperation[op]);
463 OwnPtr<WebKit::WebCryptoAlgorithmParams> params;
464 if (!parseAlgorithmParams(raw, paramsType, params, context, es))
465 return false;
466
467 algorithm = WebKit::WebCryptoAlgorithm(info->algorithmId, info->algorithmNam e, params.release());
468 return true;
469 }
470
471 } // namespace
472
293 bool normalizeAlgorithm(const Dictionary& raw, AlgorithmOperation op, WebKit::We bCryptoAlgorithm& algorithm, ExceptionState& es) 473 bool normalizeAlgorithm(const Dictionary& raw, AlgorithmOperation op, WebKit::We bCryptoAlgorithm& algorithm, ExceptionState& es)
294 { 474 {
295 const AlgorithmInfo* info = algorithmInfo(raw, es); 475 return normalizeAlgorithm(raw, op, algorithm, ExceptionContext(), es);
296 if (!info)
297 return false;
298
299 if (info->paramsForOperation[op] == UnsupportedOp) {
300 es.throwDOMException(NotSupportedError);
301 return false;
302 }
303
304 WebKit::WebCryptoAlgorithmParamsType paramsType = static_cast<WebKit::WebCry ptoAlgorithmParamsType>(info->paramsForOperation[op]);
305 OwnPtr<WebKit::WebCryptoAlgorithmParams> params = parseAlgorithmParams(raw, paramsType);
306
307 if (!params && paramsType != WebKit::WebCryptoAlgorithmParamsTypeNone) {
308 es.throwDOMException(NotSupportedError);
309 return false;
310 }
311
312 algorithm = WebKit::WebCryptoAlgorithm(info->algorithmId, info->algorithmNam e, params.release());
313 return true;
314 } 476 }
315 477
316 } // namespace WebCore 478 } // namespace WebCore
OLDNEW
« no previous file with comments | « LayoutTests/crypto/sign-verify-expected.txt ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698