Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / crypto / NormalizeAlgorithm.cpp
1 /*
2  * Copyright (C) 2013 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "modules/crypto/NormalizeAlgorithm.h"
33
34 #include "bindings/core/v8/Dictionary.h"
35 #include "platform/NotImplemented.h"
36 #include "public/platform/WebCryptoAlgorithmParams.h"
37 #include "public/platform/WebString.h"
38 #include "wtf/ArrayBuffer.h"
39 #include "wtf/ArrayBufferView.h"
40 #include "wtf/MathExtras.h"
41 #include "wtf/Uint8Array.h"
42 #include "wtf/Vector.h"
43 #include "wtf/text/StringBuilder.h"
44 #include <algorithm>
45
46 namespace blink {
47
48 namespace {
49
50 struct AlgorithmNameMapping {
51     // Must be an upper case ASCII string.
52     const char* const algorithmName;
53     // Must be strlen(algorithmName).
54     unsigned char algorithmNameLength;
55     WebCryptoAlgorithmId algorithmId;
56
57 #if ENABLE(ASSERT)
58     bool operator<(const AlgorithmNameMapping&) const;
59 #endif
60 };
61
62 // Must be sorted by length, and then by reverse string.
63 // Also all names must be upper case ASCII.
64 const AlgorithmNameMapping algorithmNameMappings[] = {
65     {"HMAC", 4, WebCryptoAlgorithmIdHmac},
66     {"SHA-1", 5, WebCryptoAlgorithmIdSha1},
67     {"AES-KW", 6, WebCryptoAlgorithmIdAesKw},
68     {"SHA-512", 7, WebCryptoAlgorithmIdSha512},
69     {"SHA-384", 7, WebCryptoAlgorithmIdSha384},
70     {"SHA-256", 7, WebCryptoAlgorithmIdSha256},
71     {"AES-CBC", 7, WebCryptoAlgorithmIdAesCbc},
72     {"AES-GCM", 7, WebCryptoAlgorithmIdAesGcm},
73     {"AES-CTR", 7, WebCryptoAlgorithmIdAesCtr},
74     {"RSA-OAEP", 8, WebCryptoAlgorithmIdRsaOaep},
75     {"RSASSA-PKCS1-V1_5", 17, WebCryptoAlgorithmIdRsaSsaPkcs1v1_5},
76 };
77
78 #if ENABLE(ASSERT)
79
80 // Essentially std::is_sorted() (however that function is new to C++11).
81 template <typename Iterator>
82 bool isSorted(Iterator begin, Iterator end)
83 {
84     if (begin == end)
85         return true;
86
87     Iterator prev = begin;
88     Iterator cur = begin + 1;
89
90     while (cur != end) {
91         if (*cur < *prev)
92             return false;
93         cur++;
94         prev++;
95     }
96
97     return true;
98 }
99
100 bool AlgorithmNameMapping::operator<(const AlgorithmNameMapping& o) const
101 {
102     if (algorithmNameLength < o.algorithmNameLength)
103         return true;
104     if (algorithmNameLength > o.algorithmNameLength)
105         return false;
106
107     for (size_t i = 0; i < algorithmNameLength; ++i) {
108         size_t reverseIndex = algorithmNameLength - i - 1;
109         char c1 = algorithmName[reverseIndex];
110         char c2 = o.algorithmName[reverseIndex];
111
112         if (c1 < c2)
113             return true;
114         if (c1 > c2)
115             return false;
116     }
117
118     return false;
119 }
120
121 bool verifyAlgorithmNameMappings(const AlgorithmNameMapping* begin, const AlgorithmNameMapping* end)
122 {
123     for (const AlgorithmNameMapping* it = begin; it != end; ++it) {
124         if (it->algorithmNameLength != strlen(it->algorithmName))
125             return false;
126         String str(it->algorithmName, it->algorithmNameLength);
127         if (!str.containsOnlyASCII())
128             return false;
129         if (str.upper() != str)
130             return false;
131     }
132
133     return isSorted(begin, end);
134 }
135 #endif
136
137 template <typename CharType>
138 bool algorithmNameComparator(const AlgorithmNameMapping& a, StringImpl* b)
139 {
140     if (a.algorithmNameLength < b->length())
141         return true;
142     if (a.algorithmNameLength > b->length())
143         return false;
144
145     // Because the algorithm names contain many common prefixes, it is better
146     // to compare starting at the end of the string.
147     for (size_t i = 0; i < a.algorithmNameLength; ++i) {
148         size_t reverseIndex = a.algorithmNameLength - i - 1;
149         CharType c1 = a.algorithmName[reverseIndex];
150         CharType c2 = b->getCharacters<CharType>()[reverseIndex];
151         if (!isASCII(c2))
152             return false;
153         c2 = toASCIIUpper(c2);
154
155         if (c1 < c2)
156             return true;
157         if (c1 > c2)
158             return false;
159     }
160
161     return false;
162 }
163
164 bool lookupAlgorithmIdByName(const String& algorithmName, WebCryptoAlgorithmId& id)
165 {
166     const AlgorithmNameMapping* begin = algorithmNameMappings;
167     const AlgorithmNameMapping* end = algorithmNameMappings + WTF_ARRAY_LENGTH(algorithmNameMappings);
168
169     ASSERT(verifyAlgorithmNameMappings(begin, end));
170
171     const AlgorithmNameMapping* it;
172     if (algorithmName.impl()->is8Bit())
173         it = std::lower_bound(begin, end, algorithmName.impl(), &algorithmNameComparator<LChar>);
174     else
175         it = std::lower_bound(begin, end, algorithmName.impl(), &algorithmNameComparator<UChar>);
176
177     if (it == end)
178         return false;
179
180     if (it->algorithmNameLength != algorithmName.length() || !equalIgnoringCase(algorithmName, it->algorithmName))
181         return false;
182
183     id = it->algorithmId;
184     return true;
185 }
186
187 void setSyntaxError(const String& message, AlgorithmError* error)
188 {
189     error->errorType = WebCryptoErrorTypeSyntax;
190     error->errorDetails = message;
191 }
192
193 void setNotSupportedError(const String& message, AlgorithmError* error)
194 {
195     error->errorType = WebCryptoErrorTypeNotSupported;
196     error->errorDetails = message;
197 }
198
199 void setDataError(const String& message, AlgorithmError* error)
200 {
201     error->errorType = WebCryptoErrorTypeData;
202     error->errorDetails = message;
203 }
204
205 // ErrorContext holds a stack of string literals which describe what was
206 // happening at the time the error occurred. This is helpful because
207 // parsing of the algorithm dictionary can be recursive and it is difficult to
208 // tell what went wrong from a failure alone.
209 class ErrorContext {
210 public:
211     void add(const char* message)
212     {
213         m_messages.append(message);
214     }
215
216     void removeLast()
217     {
218         m_messages.removeLast();
219     }
220
221     // Join all of the string literals into a single String.
222     String toString() const
223     {
224         if (m_messages.isEmpty())
225             return String();
226
227         StringBuilder result;
228         const char* Separator = ": ";
229
230         size_t length = (m_messages.size() - 1) * strlen(Separator);
231         for (size_t i = 0; i < m_messages.size(); ++i)
232             length += strlen(m_messages[i]);
233         result.reserveCapacity(length);
234
235         for (size_t i = 0; i < m_messages.size(); ++i) {
236             if (i)
237                 result.append(Separator, strlen(Separator));
238             result.append(m_messages[i], strlen(m_messages[i]));
239         }
240
241         return result.toString();
242     }
243
244     String toString(const char* message) const
245     {
246         ErrorContext stack(*this);
247         stack.add(message);
248         return stack.toString();
249     }
250
251     String toString(const char* message1, const char* message2) const
252     {
253         ErrorContext stack(*this);
254         stack.add(message1);
255         stack.add(message2);
256         return stack.toString();
257     }
258
259 private:
260     // This inline size is large enough to avoid having to grow the Vector in
261     // the majority of cases (up to 1 nested algorithm identifier).
262     Vector<const char*, 10> m_messages;
263 };
264
265 // Defined by the WebCrypto spec as:
266 //
267 //     typedef (ArrayBuffer or ArrayBufferView) CryptoOperationData;
268 //
269 // FIXME: Currently only supports ArrayBufferView.
270 bool getOptionalCryptoOperationData(const Dictionary& raw, const char* propertyName, bool& hasProperty, RefPtr<ArrayBufferView>& buffer, const ErrorContext& context, AlgorithmError* error)
271 {
272     if (!DictionaryHelper::get(raw, propertyName, buffer)) {
273         hasProperty = false;
274         return true;
275     }
276
277     hasProperty = true;
278
279     if (!buffer) {
280         setSyntaxError(context.toString(propertyName, "Not an ArrayBufferView"), error);
281         return false;
282     }
283
284     return true;
285 }
286
287 // Defined by the WebCrypto spec as:
288 //
289 //     typedef (ArrayBuffer or ArrayBufferView) CryptoOperationData;
290 //
291 // FIXME: Currently only supports ArrayBufferView.
292 bool getCryptoOperationData(const Dictionary& raw, const char* propertyName, RefPtr<ArrayBufferView>& buffer, const ErrorContext& context, AlgorithmError* error)
293 {
294     bool hasProperty;
295     bool ok = getOptionalCryptoOperationData(raw, propertyName, hasProperty, buffer, context, error);
296     if (!hasProperty) {
297         setSyntaxError(context.toString(propertyName, "Missing required property"), error);
298         return false;
299     }
300     return ok;
301 }
302
303 bool getUint8Array(const Dictionary& raw, const char* propertyName, RefPtr<Uint8Array>& array, const ErrorContext& context, AlgorithmError* error)
304 {
305     if (!DictionaryHelper::get(raw, propertyName, array) || !array) {
306         setSyntaxError(context.toString(propertyName, "Missing or not a Uint8Array"), error);
307         return false;
308     }
309     return true;
310 }
311
312 // Defined by the WebCrypto spec as:
313 //
314 //     typedef Uint8Array BigInteger;
315 bool getBigInteger(const Dictionary& raw, const char* propertyName, RefPtr<Uint8Array>& array, const ErrorContext& context, AlgorithmError* error)
316 {
317     if (!getUint8Array(raw, propertyName, array, context, error))
318         return false;
319
320     if (!array->byteLength()) {
321         setSyntaxError(context.toString(propertyName, "BigInteger should not be empty"), error);
322         return false;
323     }
324
325     if (!DictionaryHelper::get(raw, propertyName, array) || !array) {
326         setSyntaxError(context.toString(propertyName, "Missing or not a Uint8Array"), error);
327         return false;
328     }
329     return true;
330 }
331
332 // Gets an integer according to WebIDL's [EnforceRange].
333 bool getOptionalInteger(const Dictionary& raw, const char* propertyName, bool& hasProperty, double& value, double minValue, double maxValue, const ErrorContext& context, AlgorithmError* error)
334 {
335     double number;
336     bool ok = DictionaryHelper::get(raw, propertyName, number, hasProperty);
337
338     if (!hasProperty)
339         return true;
340
341     if (!ok || std::isnan(number)) {
342         setSyntaxError(context.toString(propertyName, "Is not a number"), error);
343         return false;
344     }
345
346     number = trunc(number);
347
348     if (std::isinf(number) || number < minValue || number > maxValue) {
349         setSyntaxError(context.toString(propertyName, "Outside of numeric range"), error);
350         return false;
351     }
352
353     value = number;
354     return true;
355 }
356
357 bool getInteger(const Dictionary& raw, const char* propertyName, double& value, double minValue, double maxValue, const ErrorContext& context, AlgorithmError* error)
358 {
359     bool hasProperty;
360     if (!getOptionalInteger(raw, propertyName, hasProperty, value, minValue, maxValue, context, error))
361         return false;
362
363     if (!hasProperty) {
364         setSyntaxError(context.toString(propertyName, "Missing required property"), error);
365         return false;
366     }
367
368     return true;
369 }
370
371 bool getUint32(const Dictionary& raw, const char* propertyName, uint32_t& value, const ErrorContext& context, AlgorithmError* error)
372 {
373     double number;
374     if (!getInteger(raw, propertyName, number, 0, 0xFFFFFFFF, context, error))
375         return false;
376     value = number;
377     return true;
378 }
379
380 bool getUint16(const Dictionary& raw, const char* propertyName, uint16_t& value, const ErrorContext& context, AlgorithmError* error)
381 {
382     double number;
383     if (!getInteger(raw, propertyName, number, 0, 0xFFFF, context, error))
384         return false;
385     value = number;
386     return true;
387 }
388
389 bool getUint8(const Dictionary& raw, const char* propertyName, uint8_t& value, const ErrorContext& context, AlgorithmError* error)
390 {
391     double number;
392     if (!getInteger(raw, propertyName, number, 0, 0xFF, context, error))
393         return false;
394     value = number;
395     return true;
396 }
397
398 bool getOptionalUint32(const Dictionary& raw, const char* propertyName, bool& hasValue, uint32_t& value, const ErrorContext& context, AlgorithmError* error)
399 {
400     double number;
401     if (!getOptionalInteger(raw, propertyName, hasValue, number, 0, 0xFFFFFFFF, context, error))
402         return false;
403     if (hasValue)
404         value = number;
405     return true;
406 }
407
408 // Defined by the WebCrypto spec as:
409 //
410 //    dictionary AesCbcParams : Algorithm {
411 //      CryptoOperationData iv;
412 //    };
413 bool parseAesCbcParams(const Dictionary& raw, OwnPtr<WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
414 {
415     RefPtr<ArrayBufferView> iv;
416     if (!getCryptoOperationData(raw, "iv", iv, context, error))
417         return false;
418
419     if (iv->byteLength() != 16) {
420         setDataError(context.toString("iv", "Must be 16 bytes"), error);
421         return false;
422     }
423
424     params = adoptPtr(new WebCryptoAesCbcParams(static_cast<unsigned char*>(iv->baseAddress()), iv->byteLength()));
425     return true;
426 }
427
428 // Defined by the WebCrypto spec as:
429 //
430 //    dictionary AesKeyGenParams : Algorithm {
431 //      [EnforceRange] unsigned short length;
432 //    };
433 bool parseAesKeyGenParams(const Dictionary& raw, OwnPtr<WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
434 {
435     uint16_t length;
436     if (!getUint16(raw, "length", length, context, error))
437         return false;
438
439     params = adoptPtr(new WebCryptoAesKeyGenParams(length));
440     return true;
441 }
442
443 bool parseAlgorithm(const Dictionary&, WebCryptoOperation, WebCryptoAlgorithm&, ErrorContext, AlgorithmError*);
444
445 bool parseHash(const Dictionary& raw, WebCryptoAlgorithm& hash, ErrorContext context, AlgorithmError* error)
446 {
447     Dictionary rawHash;
448     if (!DictionaryHelper::get(raw, "hash", rawHash)) {
449         setSyntaxError(context.toString("hash", "Missing or not a dictionary"), error);
450         return false;
451     }
452
453     context.add("hash");
454     return parseAlgorithm(rawHash, WebCryptoOperationDigest, hash, context, error);
455 }
456
457 // Defined by the WebCrypto spec as:
458 //
459 //    dictionary HmacImportParams : Algorithm {
460 //      AlgorithmIdentifier hash;
461 //    };
462 bool parseHmacImportParams(const Dictionary& raw, OwnPtr<WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
463 {
464     WebCryptoAlgorithm hash;
465     if (!parseHash(raw, hash, context, error))
466         return false;
467
468     params = adoptPtr(new WebCryptoHmacImportParams(hash));
469     return true;
470 }
471
472 // Defined by the WebCrypto spec as:
473 //
474 //    dictionary HmacKeyGenParams : Algorithm {
475 //      AlgorithmIdentifier hash;
476 //      // The length (in bits) of the key to generate. If unspecified, the
477 //      // recommended length will be used, which is the size of the associated hash function's block
478 //      // size.
479 //      unsigned long length;
480 //    };
481 bool parseHmacKeyGenParams(const Dictionary& raw, OwnPtr<WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
482 {
483     WebCryptoAlgorithm hash;
484     if (!parseHash(raw, hash, context, error))
485         return false;
486
487     bool hasLength;
488     uint32_t length = 0;
489     if (!getOptionalUint32(raw, "length", hasLength, length, context, error))
490         return false;
491
492     params = adoptPtr(new WebCryptoHmacKeyGenParams(hash, hasLength, length));
493     return true;
494 }
495
496 // Defined by the WebCrypto spec as:
497 //
498 //    dictionary RsaHashedImportParams {
499 //      AlgorithmIdentifier hash;
500 //    };
501 bool parseRsaHashedImportParams(const Dictionary& raw, OwnPtr<WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
502 {
503     WebCryptoAlgorithm hash;
504     if (!parseHash(raw, hash, context, error))
505         return false;
506
507     params = adoptPtr(new WebCryptoRsaHashedImportParams(hash));
508     return true;
509 }
510
511 // Defined by the WebCrypto spec as:
512 //
513 //    dictionary RsaHashedKeyGenParams : RsaKeyGenParams {
514 //      AlgorithmIdentifier hash;
515 //    };
516 //
517 //    dictionary RsaKeyGenParams : Algorithm {
518 //      unsigned long modulusLength;
519 //      BigInteger publicExponent;
520 //    };
521 bool parseRsaHashedKeyGenParams(const Dictionary& raw, OwnPtr<WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
522 {
523     uint32_t modulusLength;
524     if (!getUint32(raw, "modulusLength", modulusLength, context, error))
525         return false;
526
527     RefPtr<Uint8Array> publicExponent;
528     if (!getBigInteger(raw, "publicExponent", publicExponent, context, error))
529         return false;
530
531     WebCryptoAlgorithm hash;
532     if (!parseHash(raw, hash, context, error))
533         return false;
534
535     params = adoptPtr(new WebCryptoRsaHashedKeyGenParams(hash, modulusLength, static_cast<const unsigned char*>(publicExponent->baseAddress()), publicExponent->byteLength()));
536     return true;
537 }
538
539 // Defined by the WebCrypto spec as:
540 //
541 //    dictionary AesCtrParams : Algorithm {
542 //      CryptoOperationData counter;
543 //      [EnforceRange] octet length;
544 //    };
545 bool parseAesCtrParams(const Dictionary& raw, OwnPtr<WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
546 {
547     RefPtr<ArrayBufferView> counter;
548     if (!getCryptoOperationData(raw, "counter", counter, context, error))
549         return false;
550
551     uint8_t length;
552     if (!getUint8(raw, "length", length, context, error))
553         return false;
554
555     params = adoptPtr(new WebCryptoAesCtrParams(length, static_cast<const unsigned char*>(counter->baseAddress()), counter->byteLength()));
556     return true;
557 }
558
559 // Defined by the WebCrypto spec as:
560 //
561 //     dictionary AesGcmParams : Algorithm {
562 //       CryptoOperationData iv;
563 //       CryptoOperationData? additionalData;
564 //       [EnforceRange] octet? tagLength;  // May be 0-128
565 //     }
566 bool parseAesGcmParams(const Dictionary& raw, OwnPtr<WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
567 {
568     RefPtr<ArrayBufferView> iv;
569     if (!getCryptoOperationData(raw, "iv", iv, context, error))
570         return false;
571
572     bool hasAdditionalData;
573     RefPtr<ArrayBufferView> additionalData;
574     if (!getOptionalCryptoOperationData(raw, "additionalData", hasAdditionalData, additionalData, context, error))
575         return false;
576
577     double tagLength;
578     bool hasTagLength;
579     if (!getOptionalInteger(raw, "tagLength", hasTagLength, tagLength, 0, 128, context, error))
580         return false;
581
582     const unsigned char* ivStart = static_cast<const unsigned char*>(iv->baseAddress());
583     unsigned ivLength = iv->byteLength();
584
585     const unsigned char* additionalDataStart = hasAdditionalData ? static_cast<const unsigned char*>(additionalData->baseAddress()) : 0;
586     unsigned additionalDataLength = hasAdditionalData ? additionalData->byteLength() : 0;
587
588     params = adoptPtr(new WebCryptoAesGcmParams(ivStart, ivLength, hasAdditionalData, additionalDataStart, additionalDataLength, hasTagLength, tagLength));
589     return true;
590 }
591
592 // Defined by the WebCrypto spec as:
593 //
594 //     dictionary RsaOaepParams : Algorithm {
595 //       CryptoOperationData? label;
596 //     };
597 bool parseRsaOaepParams(const Dictionary& raw, OwnPtr<WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
598 {
599     bool hasLabel;
600     RefPtr<ArrayBufferView> label;
601     if (!getOptionalCryptoOperationData(raw, "label", hasLabel, label, context, error))
602         return false;
603
604     const unsigned char* labelStart = hasLabel ? static_cast<const unsigned char*>(label->baseAddress()) : 0;
605     unsigned labelLength = hasLabel ? label->byteLength() : 0;
606
607     params = adoptPtr(new WebCryptoRsaOaepParams(hasLabel, labelStart, labelLength));
608     return true;
609 }
610
611 bool parseAlgorithmParams(const Dictionary& raw, WebCryptoAlgorithmParamsType type, OwnPtr<WebCryptoAlgorithmParams>& params, ErrorContext& context, AlgorithmError* error)
612 {
613     switch (type) {
614     case WebCryptoAlgorithmParamsTypeNone:
615         return true;
616     case WebCryptoAlgorithmParamsTypeAesCbcParams:
617         context.add("AesCbcParams");
618         return parseAesCbcParams(raw, params, context, error);
619     case WebCryptoAlgorithmParamsTypeAesKeyGenParams:
620         context.add("AesKeyGenParams");
621         return parseAesKeyGenParams(raw, params, context, error);
622     case WebCryptoAlgorithmParamsTypeHmacImportParams:
623         context.add("HmacImportParams");
624         return parseHmacImportParams(raw, params, context, error);
625     case WebCryptoAlgorithmParamsTypeHmacKeyGenParams:
626         context.add("HmacKeyGenParams");
627         return parseHmacKeyGenParams(raw, params, context, error);
628     case WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams:
629         context.add("RsaHashedKeyGenParams");
630         return parseRsaHashedKeyGenParams(raw, params, context, error);
631     case WebCryptoAlgorithmParamsTypeRsaHashedImportParams:
632         context.add("RsaHashedImportParams");
633         return parseRsaHashedImportParams(raw, params, context, error);
634     case WebCryptoAlgorithmParamsTypeAesCtrParams:
635         context.add("AesCtrParams");
636         return parseAesCtrParams(raw, params, context, error);
637     case WebCryptoAlgorithmParamsTypeAesGcmParams:
638         context.add("AesGcmParams");
639         return parseAesGcmParams(raw, params, context, error);
640     case WebCryptoAlgorithmParamsTypeRsaOaepParams:
641         context.add("RsaOaepParams");
642         return parseRsaOaepParams(raw, params, context, error);
643         break;
644     }
645     ASSERT_NOT_REACHED();
646     return false;
647 }
648
649 const char* operationToString(WebCryptoOperation op)
650 {
651     switch (op) {
652     case WebCryptoOperationEncrypt:
653         return "encrypt";
654     case WebCryptoOperationDecrypt:
655         return "decrypt";
656     case WebCryptoOperationSign:
657         return "sign";
658     case WebCryptoOperationVerify:
659         return "verify";
660     case WebCryptoOperationDigest:
661         return "digest";
662     case WebCryptoOperationGenerateKey:
663         return "generateKey";
664     case WebCryptoOperationImportKey:
665         return "importKey";
666     case WebCryptoOperationDeriveKey:
667         return "deriveKey";
668     case WebCryptoOperationDeriveBits:
669         return "deriveBits";
670     case WebCryptoOperationWrapKey:
671         return "wrapKey";
672     case WebCryptoOperationUnwrapKey:
673         return "unwrapKey";
674     }
675     return 0;
676 }
677
678 bool parseAlgorithm(const Dictionary& raw, WebCryptoOperation op, WebCryptoAlgorithm& algorithm, ErrorContext context, AlgorithmError* error)
679 {
680     context.add("Algorithm");
681
682     if (!raw.isObject()) {
683         setSyntaxError(context.toString("Not an object"), error);
684         return false;
685     }
686
687     String algorithmName;
688     if (!DictionaryHelper::get(raw, "name", algorithmName)) {
689         setSyntaxError(context.toString("name", "Missing or not a string"), error);
690         return false;
691     }
692
693     WebCryptoAlgorithmId algorithmId;
694     if (!lookupAlgorithmIdByName(algorithmName, algorithmId)) {
695         // FIXME: The spec says to return a SyntaxError if the input contains
696         //        any non-ASCII characters.
697         setNotSupportedError(context.toString("Unrecognized name"), error);
698         return false;
699     }
700
701     // Remove the "Algorithm:" prefix for all subsequent errors.
702     context.removeLast();
703
704     const WebCryptoAlgorithmInfo* algorithmInfo = WebCryptoAlgorithm::lookupAlgorithmInfo(algorithmId);
705
706     if (algorithmInfo->operationToParamsType[op] == WebCryptoAlgorithmInfo::Undefined) {
707         context.add(algorithmInfo->name);
708         setNotSupportedError(context.toString("Unsupported operation", operationToString(op)), error);
709         return false;
710     }
711
712     WebCryptoAlgorithmParamsType paramsType = static_cast<WebCryptoAlgorithmParamsType>(algorithmInfo->operationToParamsType[op]);
713
714     OwnPtr<WebCryptoAlgorithmParams> params;
715     if (!parseAlgorithmParams(raw, paramsType, params, context, error))
716         return false;
717
718     algorithm = WebCryptoAlgorithm(algorithmId, params.release());
719     return true;
720 }
721
722 } // namespace
723
724 bool normalizeAlgorithm(const Dictionary& raw, WebCryptoOperation op, WebCryptoAlgorithm& algorithm, AlgorithmError* error)
725 {
726     return parseAlgorithm(raw, op, algorithm, ErrorContext(), error);
727 }
728
729 } // namespace blink