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

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