OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |