Upstream version 7.36.149.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/v8/Dictionary.h"
35 #include "platform/CryptoResult.h"
36 #include "platform/NotImplemented.h"
37 #include "public/platform/WebCryptoAlgorithmParams.h"
38 #include "public/platform/WebString.h"
39 #include "wtf/ArrayBuffer.h"
40 #include "wtf/ArrayBufferView.h"
41 #include "wtf/MathExtras.h"
42 #include "wtf/Uint8Array.h"
43 #include "wtf/Vector.h"
44 #include "wtf/text/StringBuilder.h"
45 #include <algorithm>
46
47 namespace WebCore {
48
49 namespace {
50
51 struct AlgorithmNameMapping {
52     // Must be an upper case ASCII string.
53     const char* const algorithmName;
54     // Must be strlen(algorithmName).
55     unsigned char algorithmNameLength;
56     blink::WebCryptoAlgorithmId algorithmId;
57
58 #if ASSERT_ENABLED
59     bool operator<(const AlgorithmNameMapping&) const;
60 #endif
61 };
62
63 // Must be sorted by length, and then by reverse string.
64 // Also all names must be upper case ASCII.
65 const AlgorithmNameMapping algorithmNameMappings[] = {
66     {"HMAC", 4, blink::WebCryptoAlgorithmIdHmac},
67     {"SHA-1", 5, blink::WebCryptoAlgorithmIdSha1},
68     {"AES-KW", 6, blink::WebCryptoAlgorithmIdAesKw},
69     {"SHA-512", 7, blink::WebCryptoAlgorithmIdSha512},
70     {"SHA-384", 7, blink::WebCryptoAlgorithmIdSha384},
71     {"SHA-256", 7, blink::WebCryptoAlgorithmIdSha256},
72     {"AES-CBC", 7, blink::WebCryptoAlgorithmIdAesCbc},
73     {"AES-GCM", 7, blink::WebCryptoAlgorithmIdAesGcm},
74     {"AES-CTR", 7, blink::WebCryptoAlgorithmIdAesCtr},
75     {"RSAES-PKCS1-V1_5", 16, blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5},
76     {"RSASSA-PKCS1-V1_5", 17, blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5},
77 };
78
79 typedef char ParamsTypeOrUndefined;
80 const ParamsTypeOrUndefined Undefined = -1;
81
82 struct AlgorithmInfo {
83     // The canonical (case-sensitive) name for the algorithm.
84     const char* name;
85
86     // A map from the operation to the expected parameter type of the algorithm.
87     // If an operation is not applicable for the algorithm, set to Undefined.
88     const ParamsTypeOrUndefined operationToParamsType[LastAlgorithmOperation + 1];
89 };
90
91 // A mapping from the algorithm ID to information about the algorithm.
92 const AlgorithmInfo algorithmIdToInfo[] = {
93     { // Index 0
94         "AES-CBC", {
95             blink::WebCryptoAlgorithmParamsTypeAesCbcParams, // Encrypt
96             blink::WebCryptoAlgorithmParamsTypeAesCbcParams, // Decrypt
97             Undefined, // Sign
98             Undefined, // Verify
99             Undefined, // Digest
100             blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams, // GenerateKey
101             blink::WebCryptoAlgorithmParamsTypeNone, // ImportKey
102             Undefined, // DeriveKey
103             Undefined, // DeriveBits
104             blink::WebCryptoAlgorithmParamsTypeAesCbcParams, // WrapKey
105             blink::WebCryptoAlgorithmParamsTypeAesCbcParams // UnwrapKey
106         }
107     }, { // Index 1
108         "HMAC", {
109             Undefined, // Encrypt
110             Undefined, // Decrypt
111             blink::WebCryptoAlgorithmParamsTypeNone, // Sign
112             blink::WebCryptoAlgorithmParamsTypeNone, // Verify
113             Undefined, // Digest
114             blink::WebCryptoAlgorithmParamsTypeHmacKeyGenParams, // GenerateKey
115             blink::WebCryptoAlgorithmParamsTypeHmacImportParams, // ImportKey
116             Undefined, // DeriveKey
117             Undefined, // DeriveBits
118             Undefined, // WrapKey
119             Undefined // UnwrapKey
120         }
121     }, { // Index 2
122         "RSASSA-PKCS1-v1_5", {
123             Undefined, // Encrypt
124             Undefined, // Decrypt
125             blink::WebCryptoAlgorithmParamsTypeNone, // Sign
126             blink::WebCryptoAlgorithmParamsTypeNone, // Verify
127             Undefined, // Digest
128             blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams, // GenerateKey
129             blink::WebCryptoAlgorithmParamsTypeRsaHashedImportParams, // ImportKey
130             Undefined, // DeriveKey
131             Undefined, // DeriveBits
132             Undefined, // WrapKey
133             Undefined // UnwrapKey
134         }
135     }, { // Index 3
136         "RSAES-PKCS1-v1_5", {
137             blink::WebCryptoAlgorithmParamsTypeNone, // Encrypt
138             blink::WebCryptoAlgorithmParamsTypeNone, // Decrypt
139             Undefined, // Sign
140             Undefined, // Verify
141             Undefined, // Digest
142             blink::WebCryptoAlgorithmParamsTypeRsaKeyGenParams, // GenerateKey
143             blink::WebCryptoAlgorithmParamsTypeNone, // ImportKey
144             Undefined, // DeriveKey
145             Undefined, // DeriveBits
146             blink::WebCryptoAlgorithmParamsTypeNone, // WrapKey
147             blink::WebCryptoAlgorithmParamsTypeNone // UnwrapKey
148         }
149     }, { // Index 4
150         "SHA-1", {
151             Undefined, // Encrypt
152             Undefined, // Decrypt
153             Undefined, // Sign
154             Undefined, // Verify
155             blink::WebCryptoAlgorithmParamsTypeNone, // Digest
156             Undefined, // GenerateKey
157             Undefined, // ImportKey
158             Undefined, // DeriveKey
159             Undefined, // DeriveBits
160             Undefined, // WrapKey
161             Undefined // UnwrapKey
162         }
163     }, { // Index 5
164         "SHA-256", {
165             Undefined, // Encrypt
166             Undefined, // Decrypt
167             Undefined, // Sign
168             Undefined, // Verify
169             blink::WebCryptoAlgorithmParamsTypeNone, // Digest
170             Undefined, // GenerateKey
171             Undefined, // ImportKey
172             Undefined, // DeriveKey
173             Undefined, // DeriveBits
174             Undefined, // WrapKey
175             Undefined // UnwrapKey
176         }
177     }, { // Index 6
178         "SHA-384", {
179             Undefined, // Encrypt
180             Undefined, // Decrypt
181             Undefined, // Sign
182             Undefined, // Verify
183             blink::WebCryptoAlgorithmParamsTypeNone, // Digest
184             Undefined, // GenerateKey
185             Undefined, // ImportKey
186             Undefined, // DeriveKey
187             Undefined, // DeriveBits
188             Undefined, // WrapKey
189             Undefined // UnwrapKey
190         }
191     }, { // Index 7
192         "SHA-512", {
193             Undefined, // Encrypt
194             Undefined, // Decrypt
195             Undefined, // Sign
196             Undefined, // Verify
197             blink::WebCryptoAlgorithmParamsTypeNone, // Digest
198             Undefined, // GenerateKey
199             Undefined, // ImportKey
200             Undefined, // DeriveKey
201             Undefined, // DeriveBits
202             Undefined, // WrapKey
203             Undefined // UnwrapKey
204         }
205     }, { // Index 8
206         "AES-GCM", {
207             blink::WebCryptoAlgorithmParamsTypeAesGcmParams, // Encrypt
208             blink::WebCryptoAlgorithmParamsTypeAesGcmParams, // Decrypt
209             Undefined, // Sign
210             Undefined, // Verify
211             Undefined, // Digest
212             blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams, // GenerateKey
213             blink::WebCryptoAlgorithmParamsTypeNone, // ImportKey
214             Undefined, // DeriveKey
215             Undefined, // DeriveBits
216             blink::WebCryptoAlgorithmParamsTypeAesGcmParams, // WrapKey
217             blink::WebCryptoAlgorithmParamsTypeAesGcmParams // UnwrapKey
218         }
219     }, { // Index 9
220         "RSA-OAEP", {
221             // FIXME:
222             Undefined, // Encrypt
223             Undefined, // Decrypt
224             Undefined, // Sign
225             Undefined, // Verify
226             Undefined, // Digest
227             Undefined, // GenerateKey
228             Undefined, // ImportKey
229             Undefined, // DeriveKey
230             Undefined, // DeriveBits
231             Undefined, // WrapKey
232             Undefined // UnwrapKey
233         }
234     }, { // Index 10
235         "AES-CTR", {
236             blink::WebCryptoAlgorithmParamsTypeAesCtrParams, // Encrypt
237             blink::WebCryptoAlgorithmParamsTypeAesCtrParams, // Decrypt
238             Undefined, // Sign
239             Undefined, // Verify
240             Undefined, // Digest
241             blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams, // GenerateKey
242             blink::WebCryptoAlgorithmParamsTypeNone, // ImportKey
243             Undefined, // DeriveKey
244             Undefined, // DeriveBits
245             blink::WebCryptoAlgorithmParamsTypeAesCtrParams, // WrapKey
246             blink::WebCryptoAlgorithmParamsTypeAesCtrParams // UnwrapKey
247         }
248     }, { // Index 11
249         "AES-KW", {
250             Undefined, // Encrypt
251             Undefined, // Decrypt
252             Undefined, // Sign
253             Undefined, // Verify
254             Undefined, // Digest
255             blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams, // GenerateKey
256             blink::WebCryptoAlgorithmParamsTypeNone, // ImportKey
257             Undefined, // DeriveKey
258             Undefined, // DeriveBits
259             blink::WebCryptoAlgorithmParamsTypeNone, // WrapKey
260             blink::WebCryptoAlgorithmParamsTypeNone // UnwrapKey
261         }
262     },
263 };
264
265 // Initializing the algorithmIdToInfo table above depends on knowing the enum
266 // values for algorithm IDs. If those ever change, the table will need to be
267 // updated.
268 COMPILE_ASSERT(blink::WebCryptoAlgorithmIdAesCbc == 0, AesCbc_idDoesntMatch);
269 COMPILE_ASSERT(blink::WebCryptoAlgorithmIdHmac == 1, Hmac_idDoesntMatch);
270 COMPILE_ASSERT(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 == 2, RsaSsaPkcs1v1_5_idDoesntMatch);
271 COMPILE_ASSERT(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 == 3, RsaEsPkcs1v1_5_idDoesntMatch);
272 COMPILE_ASSERT(blink::WebCryptoAlgorithmIdSha1 == 4, Sha1_idDoesntMatch);
273 COMPILE_ASSERT(blink::WebCryptoAlgorithmIdSha256 == 5, Sha256_idDoesntMatch);
274 COMPILE_ASSERT(blink::WebCryptoAlgorithmIdSha384 == 6, Sha384_idDoesntMatch);
275 COMPILE_ASSERT(blink::WebCryptoAlgorithmIdSha512 == 7, Sha512_idDoesntMatch);
276 COMPILE_ASSERT(blink::WebCryptoAlgorithmIdAesGcm == 8, AesGcm_idDoesntMatch);
277 COMPILE_ASSERT(blink::WebCryptoAlgorithmIdRsaOaep == 9, RsaOaep_idDoesntMatch);
278 COMPILE_ASSERT(blink::WebCryptoAlgorithmIdAesCtr == 10, AesCtr_idDoesntMatch);
279 COMPILE_ASSERT(blink::WebCryptoAlgorithmIdAesKw == 11, AesKw_idDoesntMatch);
280 COMPILE_ASSERT(blink::WebCryptoAlgorithmIdLast == 11, Last_idDoesntMatch);
281 COMPILE_ASSERT(10 == LastAlgorithmOperation, UpdateParamsMapping);
282
283 #if ASSERT_ENABLED
284
285 // Essentially std::is_sorted() (however that function is new to C++11).
286 template <typename Iterator>
287 bool isSorted(Iterator begin, Iterator end)
288 {
289     if (begin == end)
290         return true;
291
292     Iterator prev = begin;
293     Iterator cur = begin + 1;
294
295     while (cur != end) {
296         if (*cur < *prev)
297             return false;
298         cur++;
299         prev++;
300     }
301
302     return true;
303 }
304
305 bool AlgorithmNameMapping::operator<(const AlgorithmNameMapping& o) const
306 {
307     if (algorithmNameLength < o.algorithmNameLength)
308         return true;
309     if (algorithmNameLength > o.algorithmNameLength)
310         return false;
311
312     for (size_t i = 0; i < algorithmNameLength; ++i) {
313         size_t reverseIndex = algorithmNameLength - i - 1;
314         char c1 = algorithmName[reverseIndex];
315         char c2 = o.algorithmName[reverseIndex];
316
317         if (c1 < c2)
318             return true;
319         if (c1 > c2)
320             return false;
321     }
322
323     return false;
324 }
325
326 bool verifyAlgorithmNameMappings(const AlgorithmNameMapping* begin, const AlgorithmNameMapping* end)
327 {
328     for (const AlgorithmNameMapping* it = begin; it != end; ++it) {
329         if (it->algorithmNameLength != strlen(it->algorithmName))
330             return false;
331         String str(it->algorithmName, it->algorithmNameLength);
332         if (!str.containsOnlyASCII())
333             return false;
334         if (str.upper() != str)
335             return false;
336     }
337
338     return isSorted(begin, end);
339 }
340 #endif
341
342 template <typename CharType>
343 bool algorithmNameComparator(const AlgorithmNameMapping& a, StringImpl* b)
344 {
345     if (a.algorithmNameLength < b->length())
346         return true;
347     if (a.algorithmNameLength > b->length())
348         return false;
349
350     // Because the algorithm names contain many common prefixes, it is better
351     // to compare starting at the end of the string.
352     for (size_t i = 0; i < a.algorithmNameLength; ++i) {
353         size_t reverseIndex = a.algorithmNameLength - i - 1;
354         CharType c1 = a.algorithmName[reverseIndex];
355         CharType c2 = b->getCharacters<CharType>()[reverseIndex];
356         if (!isASCII(c2))
357             return false;
358         c2 = toASCIIUpper(c2);
359
360         if (c1 < c2)
361             return true;
362         if (c1 > c2)
363             return false;
364     }
365
366     return false;
367 }
368
369 bool lookupAlgorithmIdByName(const String& algorithmName, blink::WebCryptoAlgorithmId& id)
370 {
371     const AlgorithmNameMapping* begin = algorithmNameMappings;
372     const AlgorithmNameMapping* end = algorithmNameMappings + WTF_ARRAY_LENGTH(algorithmNameMappings);
373
374     ASSERT(verifyAlgorithmNameMappings(begin, end));
375
376     const AlgorithmNameMapping* it;
377     if (algorithmName.impl()->is8Bit())
378         it = std::lower_bound(begin, end, algorithmName.impl(), &algorithmNameComparator<LChar>);
379     else
380         it = std::lower_bound(begin, end, algorithmName.impl(), &algorithmNameComparator<UChar>);
381
382     if (it == end)
383         return false;
384
385     if (it->algorithmNameLength != algorithmName.length() || !equalIgnoringCase(algorithmName, it->algorithmName))
386         return false;
387
388     id = it->algorithmId;
389     return true;
390 }
391
392 const AlgorithmInfo* lookupAlgorithmInfo(blink::WebCryptoAlgorithmId id)
393 {
394     if (id < 0 || id >= WTF_ARRAY_LENGTH(algorithmIdToInfo))
395         return 0;
396     return &algorithmIdToInfo[id];
397 }
398
399 void completeWithSyntaxError(const String& message, CryptoResult* result)
400 {
401     result->completeWithError(blink::WebCryptoErrorTypeSyntax, message);
402 }
403
404 void completeWithNotSupportedError(const String& message, CryptoResult* result)
405 {
406     result->completeWithError(blink::WebCryptoErrorTypeNotSupported, message);
407 }
408
409 void completeWithDataError(const String& message, CryptoResult* result)
410 {
411     result->completeWithError(blink::WebCryptoErrorTypeData, message);
412 }
413
414 // ErrorContext holds a stack of string literals which describe what was
415 // happening at the time the error occurred. This is helpful because
416 // parsing of the algorithm dictionary can be recursive and it is difficult to
417 // tell what went wrong from a failure alone.
418 class ErrorContext {
419 public:
420     void add(const char* message)
421     {
422         m_messages.append(message);
423     }
424
425     void removeLast()
426     {
427         m_messages.removeLast();
428     }
429
430     // Join all of the string literals into a single String.
431     String toString() const
432     {
433         if (m_messages.isEmpty())
434             return String();
435
436         StringBuilder result;
437         const char* Separator = ": ";
438
439         size_t length = (m_messages.size() - 1) * strlen(Separator);
440         for (size_t i = 0; i < m_messages.size(); ++i)
441             length += strlen(m_messages[i]);
442         result.reserveCapacity(length);
443
444         for (size_t i = 0; i < m_messages.size(); ++i) {
445             if (i)
446                 result.append(Separator, strlen(Separator));
447             result.append(m_messages[i], strlen(m_messages[i]));
448         }
449
450         return result.toString();
451     }
452
453     String toString(const char* message) const
454     {
455         ErrorContext stack(*this);
456         stack.add(message);
457         return stack.toString();
458     }
459
460     String toString(const char* message1, const char* message2) const
461     {
462         ErrorContext stack(*this);
463         stack.add(message1);
464         stack.add(message2);
465         return stack.toString();
466     }
467
468 private:
469     // This inline size is large enough to avoid having to grow the Vector in
470     // the majority of cases (up to 1 nested algorithm identifier).
471     Vector<const char*, 10> m_messages;
472 };
473
474 // Defined by the WebCrypto spec as:
475 //
476 //     typedef (ArrayBuffer or ArrayBufferView) CryptoOperationData;
477 //
478 // FIXME: Currently only supports ArrayBufferView.
479 bool getOptionalCryptoOperationData(const Dictionary& raw, const char* propertyName, bool& hasProperty, RefPtr<ArrayBufferView>& buffer, const ErrorContext& context, CryptoResult* result)
480 {
481     if (!raw.get(propertyName, buffer)) {
482         hasProperty = false;
483         return true;
484     }
485
486     hasProperty = true;
487
488     if (!buffer) {
489         completeWithSyntaxError(context.toString(propertyName, "Not an ArrayBufferView"), result);
490         return false;
491     }
492
493     return true;
494 }
495
496 // Defined by the WebCrypto spec as:
497 //
498 //     typedef (ArrayBuffer or ArrayBufferView) CryptoOperationData;
499 //
500 // FIXME: Currently only supports ArrayBufferView.
501 bool getCryptoOperationData(const Dictionary& raw, const char* propertyName, RefPtr<ArrayBufferView>& buffer, const ErrorContext& context, CryptoResult* result)
502 {
503     bool hasProperty;
504     bool ok = getOptionalCryptoOperationData(raw, propertyName, hasProperty, buffer, context, result);
505     if (!hasProperty) {
506         completeWithSyntaxError(context.toString(propertyName, "Missing required property"), result);
507         return false;
508     }
509     return ok;
510 }
511
512 bool getUint8Array(const Dictionary& raw, const char* propertyName, RefPtr<Uint8Array>& array, const ErrorContext& context, CryptoResult* result)
513 {
514     if (!raw.get(propertyName, array) || !array) {
515         completeWithSyntaxError(context.toString(propertyName, "Missing or not a Uint8Array"), result);
516         return false;
517     }
518     return true;
519 }
520
521 // Defined by the WebCrypto spec as:
522 //
523 //     typedef Uint8Array BigInteger;
524 bool getBigInteger(const Dictionary& raw, const char* propertyName, RefPtr<Uint8Array>& array, const ErrorContext& context, CryptoResult* result)
525 {
526     if (!getUint8Array(raw, propertyName, array, context, result))
527         return false;
528
529     if (!array->byteLength()) {
530         completeWithSyntaxError(context.toString(propertyName, "BigInteger should not be empty"), result);
531         return false;
532     }
533
534     if (!raw.get(propertyName, array) || !array) {
535         completeWithSyntaxError(context.toString(propertyName, "Missing or not a Uint8Array"), result);
536         return false;
537     }
538     return true;
539 }
540
541 // Gets an integer according to WebIDL's [EnforceRange].
542 bool getOptionalInteger(const Dictionary& raw, const char* propertyName, bool& hasProperty, double& value, double minValue, double maxValue, const ErrorContext& context, CryptoResult* result)
543 {
544     double number;
545     bool ok = raw.get(propertyName, number, hasProperty);
546
547     if (!hasProperty)
548         return true;
549
550     if (!ok || std::isnan(number)) {
551         completeWithSyntaxError(context.toString(propertyName, "Is not a number"), result);
552         return false;
553     }
554
555     number = trunc(number);
556
557     if (std::isinf(number) || number < minValue || number > maxValue) {
558         completeWithSyntaxError(context.toString(propertyName, "Outside of numeric range"), result);
559         return false;
560     }
561
562     value = number;
563     return true;
564 }
565
566 bool getInteger(const Dictionary& raw, const char* propertyName, double& value, double minValue, double maxValue, const ErrorContext& context, CryptoResult* result)
567 {
568     bool hasProperty;
569     if (!getOptionalInteger(raw, propertyName, hasProperty, value, minValue, maxValue, context, result))
570         return false;
571
572     if (!hasProperty) {
573         completeWithSyntaxError(context.toString(propertyName, "Missing required property"), result);
574         return false;
575     }
576
577     return true;
578 }
579
580 bool getUint32(const Dictionary& raw, const char* propertyName, uint32_t& value, const ErrorContext& context, CryptoResult* result)
581 {
582     double number;
583     if (!getInteger(raw, propertyName, number, 0, 0xFFFFFFFF, context, result))
584         return false;
585     value = number;
586     return true;
587 }
588
589 bool getUint16(const Dictionary& raw, const char* propertyName, uint16_t& value, const ErrorContext& context, CryptoResult* result)
590 {
591     double number;
592     if (!getInteger(raw, propertyName, number, 0, 0xFFFF, context, result))
593         return false;
594     value = number;
595     return true;
596 }
597
598 bool getUint8(const Dictionary& raw, const char* propertyName, uint8_t& value, const ErrorContext& context, CryptoResult* result)
599 {
600     double number;
601     if (!getInteger(raw, propertyName, number, 0, 0xFF, context, result))
602         return false;
603     value = number;
604     return true;
605 }
606
607 bool getOptionalUint32(const Dictionary& raw, const char* propertyName, bool& hasValue, uint32_t& value, const ErrorContext& context, CryptoResult* result)
608 {
609     double number;
610     if (!getOptionalInteger(raw, propertyName, hasValue, number, 0, 0xFFFFFFFF, context, result))
611         return false;
612     if (hasValue)
613         value = number;
614     return true;
615 }
616
617 // Defined by the WebCrypto spec as:
618 //
619 //    dictionary AesCbcParams : Algorithm {
620 //      CryptoOperationData iv;
621 //    };
622 bool parseAesCbcParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ErrorContext& context, CryptoResult* result)
623 {
624     RefPtr<ArrayBufferView> iv;
625     if (!getCryptoOperationData(raw, "iv", iv, context, result))
626         return false;
627
628     if (iv->byteLength() != 16) {
629         completeWithDataError(context.toString("iv", "Must be 16 bytes"), result);
630         return false;
631     }
632
633     params = adoptPtr(new blink::WebCryptoAesCbcParams(static_cast<unsigned char*>(iv->baseAddress()), iv->byteLength()));
634     return true;
635 }
636
637 // Defined by the WebCrypto spec as:
638 //
639 //    dictionary AesKeyGenParams : Algorithm {
640 //      [EnforceRange] unsigned short length;
641 //    };
642 bool parseAesKeyGenParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ErrorContext& context, CryptoResult* result)
643 {
644     uint16_t length;
645     if (!getUint16(raw, "length", length, context, result))
646         return false;
647
648     params = adoptPtr(new blink::WebCryptoAesKeyGenParams(length));
649     return true;
650 }
651
652 bool parseAlgorithm(const Dictionary&, AlgorithmOperation, blink::WebCryptoAlgorithm&, ErrorContext, CryptoResult*);
653
654 bool parseHash(const Dictionary& raw, blink::WebCryptoAlgorithm& hash, ErrorContext context, CryptoResult* result)
655 {
656     Dictionary rawHash;
657     if (!raw.get("hash", rawHash)) {
658         completeWithSyntaxError(context.toString("hash", "Missing or not a dictionary"), result);
659         return false;
660     }
661
662     context.add("hash");
663     return parseAlgorithm(rawHash, Digest, hash, context, result);
664 }
665
666 // Defined by the WebCrypto spec as:
667 //
668 //    dictionary HmacImportParams : Algorithm {
669 //      AlgorithmIdentifier hash;
670 //    };
671 bool parseHmacImportParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ErrorContext& context, CryptoResult* result)
672 {
673     blink::WebCryptoAlgorithm hash;
674     if (!parseHash(raw, hash, context, result))
675         return false;
676
677     params = adoptPtr(new blink::WebCryptoHmacImportParams(hash));
678     return true;
679 }
680
681 // Defined by the WebCrypto spec as:
682 //
683 //    dictionary HmacKeyGenParams : Algorithm {
684 //      AlgorithmIdentifier hash;
685 //      // The length (in bits) of the key to generate. If unspecified, the
686 //      // recommended length will be used, which is the size of the associated hash function's block
687 //      // size.
688 //      unsigned long length;
689 //    };
690 bool parseHmacKeyGenParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ErrorContext& context, CryptoResult* result)
691 {
692     blink::WebCryptoAlgorithm hash;
693     if (!parseHash(raw, hash, context, result))
694         return false;
695
696     bool hasLength;
697     uint32_t length = 0;
698     if (!getOptionalUint32(raw, "length", hasLength, length, context, result))
699         return false;
700
701     params = adoptPtr(new blink::WebCryptoHmacKeyGenParams(hash, hasLength, length));
702     return true;
703 }
704
705 // Defined by the WebCrypto spec as:
706 //
707 //    dictionary RsaHashedImportParams {
708 //      AlgorithmIdentifier hash;
709 //    };
710 bool parseRsaHashedImportParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ErrorContext& context, CryptoResult* result)
711 {
712     blink::WebCryptoAlgorithm hash;
713     if (!parseHash(raw, hash, context, result))
714         return false;
715
716     params = adoptPtr(new blink::WebCryptoRsaHashedImportParams(hash));
717     return true;
718 }
719
720 // Defined by the WebCrypto spec as:
721 //
722 //    dictionary RsaKeyGenParams : Algorithm {
723 //      unsigned long modulusLength;
724 //      BigInteger publicExponent;
725 //    };
726 bool parseRsaKeyGenParams(const Dictionary& raw, uint32_t& modulusLength, RefPtr<Uint8Array>& publicExponent, const ErrorContext& context, CryptoResult* result)
727 {
728     if (!getUint32(raw, "modulusLength", modulusLength, context, result))
729         return false;
730
731     if (!getBigInteger(raw, "publicExponent", publicExponent, context, result))
732         return false;
733
734     return true;
735 }
736
737 bool parseRsaKeyGenParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ErrorContext& context, CryptoResult* result)
738 {
739     uint32_t modulusLength;
740     RefPtr<Uint8Array> publicExponent;
741     if (!parseRsaKeyGenParams(raw, modulusLength, publicExponent, context, result))
742         return false;
743
744     params = adoptPtr(new blink::WebCryptoRsaKeyGenParams(modulusLength, static_cast<const unsigned char*>(publicExponent->baseAddress()), publicExponent->byteLength()));
745     return true;
746 }
747
748 // Defined by the WebCrypto spec as:
749 //
750 //    dictionary RsaHashedKeyGenParams : RsaKeyGenParams {
751 //      AlgorithmIdentifier hash;
752 //    };
753 bool parseRsaHashedKeyGenParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ErrorContext& context, CryptoResult* result)
754 {
755     uint32_t modulusLength;
756     RefPtr<Uint8Array> publicExponent;
757     if (!parseRsaKeyGenParams(raw, modulusLength, publicExponent, context, result))
758         return false;
759
760     blink::WebCryptoAlgorithm hash;
761     if (!parseHash(raw, hash, context, result))
762         return false;
763
764     params = adoptPtr(new blink::WebCryptoRsaHashedKeyGenParams(hash, modulusLength, static_cast<const unsigned char*>(publicExponent->baseAddress()), publicExponent->byteLength()));
765     return true;
766 }
767
768 // Defined by the WebCrypto spec as:
769 //
770 //    dictionary AesCtrParams : Algorithm {
771 //      CryptoOperationData counter;
772 //      [EnforceRange] octet length;
773 //    };
774 bool parseAesCtrParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ErrorContext& context, CryptoResult* result)
775 {
776     RefPtr<ArrayBufferView> counter;
777     if (!getCryptoOperationData(raw, "counter", counter, context, result))
778         return false;
779
780     uint8_t length;
781     if (!getUint8(raw, "length", length, context, result))
782         return false;
783
784     params = adoptPtr(new blink::WebCryptoAesCtrParams(length, static_cast<const unsigned char*>(counter->baseAddress()), counter->byteLength()));
785     return true;
786 }
787
788 // Defined by the WebCrypto spec as:
789 //
790 //     dictionary AesGcmParams : Algorithm {
791 //       CryptoOperationData iv;
792 //       CryptoOperationData? additionalData;
793 //       [EnforceRange] octet? tagLength;  // May be 0-128
794 //     }
795 bool parseAesGcmParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ErrorContext& context, CryptoResult* result)
796 {
797     RefPtr<ArrayBufferView> iv;
798     if (!getCryptoOperationData(raw, "iv", iv, context, result))
799         return false;
800
801     bool hasAdditionalData;
802     RefPtr<ArrayBufferView> additionalData;
803     if (!getOptionalCryptoOperationData(raw, "additionalData", hasAdditionalData, additionalData, context, result))
804         return false;
805
806     double tagLength;
807     bool hasTagLength;
808     if (!getOptionalInteger(raw, "tagLength", hasTagLength, tagLength, 0, 128, context, result))
809         return false;
810
811     const unsigned char* ivStart = static_cast<const unsigned char*>(iv->baseAddress());
812     unsigned ivLength = iv->byteLength();
813
814     const unsigned char* additionalDataStart = hasAdditionalData ? static_cast<const unsigned char*>(additionalData->baseAddress()) : 0;
815     unsigned additionalDataLength = hasAdditionalData ? additionalData->byteLength() : 0;
816
817     params = adoptPtr(new blink::WebCryptoAesGcmParams(ivStart, ivLength, hasAdditionalData, additionalDataStart, additionalDataLength, hasTagLength, tagLength));
818     return true;
819 }
820
821 bool parseAlgorithmParams(const Dictionary& raw, blink::WebCryptoAlgorithmParamsType type, OwnPtr<blink::WebCryptoAlgorithmParams>& params, ErrorContext& context, CryptoResult* result)
822 {
823     switch (type) {
824     case blink::WebCryptoAlgorithmParamsTypeNone:
825         return true;
826     case blink::WebCryptoAlgorithmParamsTypeAesCbcParams:
827         context.add("AesCbcParams");
828         return parseAesCbcParams(raw, params, context, result);
829     case blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams:
830         context.add("AesKeyGenParams");
831         return parseAesKeyGenParams(raw, params, context, result);
832     case blink::WebCryptoAlgorithmParamsTypeHmacImportParams:
833         context.add("HmacImportParams");
834         return parseHmacImportParams(raw, params, context, result);
835     case blink::WebCryptoAlgorithmParamsTypeHmacKeyGenParams:
836         context.add("HmacKeyGenParams");
837         return parseHmacKeyGenParams(raw, params, context, result);
838     case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams:
839         context.add("RsaHashedKeyGenParams");
840         return parseRsaHashedKeyGenParams(raw, params, context, result);
841     case blink::WebCryptoAlgorithmParamsTypeRsaHashedImportParams:
842         context.add("RsaHashedImportParams");
843         return parseRsaHashedImportParams(raw, params, context, result);
844     case blink::WebCryptoAlgorithmParamsTypeRsaKeyGenParams:
845         context.add("RsaKeyGenParams");
846         return parseRsaKeyGenParams(raw, params, context, result);
847     case blink::WebCryptoAlgorithmParamsTypeAesCtrParams:
848         context.add("AesCtrParams");
849         return parseAesCtrParams(raw, params, context, result);
850     case blink::WebCryptoAlgorithmParamsTypeAesGcmParams:
851         context.add("AesGcmParams");
852         return parseAesGcmParams(raw, params, context, result);
853     case blink::WebCryptoAlgorithmParamsTypeRsaOaepParams:
854         // TODO
855         notImplemented();
856         break;
857     }
858     ASSERT_NOT_REACHED();
859     return false;
860 }
861
862 const char* operationToString(AlgorithmOperation op)
863 {
864     switch (op) {
865     case Encrypt:
866         return "encrypt";
867     case Decrypt:
868         return "decrypt";
869     case Sign:
870         return "sign";
871     case Verify:
872         return "verify";
873     case Digest:
874         return "digest";
875     case GenerateKey:
876         return "generateKey";
877     case ImportKey:
878         return "importKey";
879     case DeriveKey:
880         return "deriveKey";
881     case DeriveBits:
882         return "deriveBits";
883     case WrapKey:
884         return "wrapKey";
885     case UnwrapKey:
886         return "unwrapKey";
887     }
888     return 0;
889 }
890
891 bool parseAlgorithm(const Dictionary& raw, AlgorithmOperation op, blink::WebCryptoAlgorithm& algorithm, ErrorContext context, CryptoResult* result)
892 {
893     context.add("Algorithm");
894
895     if (!raw.isObject()) {
896         completeWithSyntaxError(context.toString("Not an object"), result);
897         return false;
898     }
899
900     String algorithmName;
901     if (!raw.get("name", algorithmName)) {
902         completeWithSyntaxError(context.toString("name", "Missing or not a string"), result);
903         return false;
904     }
905
906     blink::WebCryptoAlgorithmId algorithmId;
907     if (!lookupAlgorithmIdByName(algorithmName, algorithmId)) {
908         // FIXME: The spec says to return a SyntaxError if the input contains
909         //        any non-ASCII characters.
910         completeWithNotSupportedError(context.toString("Unrecognized name"), result);
911         return false;
912     }
913
914     // Remove the "Algorithm:" prefix for all subsequent errors.
915     context.removeLast();
916
917     const AlgorithmInfo* algorithmInfo = lookupAlgorithmInfo(algorithmId);
918
919     if (algorithmInfo->operationToParamsType[op] == Undefined) {
920         context.add(algorithmIdToName(algorithmId));
921         completeWithNotSupportedError(context.toString("Unsupported operation", operationToString(op)), result);
922         return false;
923     }
924
925     blink::WebCryptoAlgorithmParamsType paramsType = static_cast<blink::WebCryptoAlgorithmParamsType>(algorithmInfo->operationToParamsType[op]);
926
927     OwnPtr<blink::WebCryptoAlgorithmParams> params;
928     if (!parseAlgorithmParams(raw, paramsType, params, context, result))
929         return false;
930
931     algorithm = blink::WebCryptoAlgorithm(algorithmId, params.release());
932     return true;
933 }
934
935 } // namespace
936
937 bool parseAlgorithm(const Dictionary& raw, AlgorithmOperation op, blink::WebCryptoAlgorithm& algorithm, CryptoResult* result)
938 {
939     return parseAlgorithm(raw, op, algorithm, ErrorContext(), result);
940 }
941
942 const char* algorithmIdToName(blink::WebCryptoAlgorithmId id)
943 {
944     return lookupAlgorithmInfo(id)->name;
945 }
946
947 } // namespace WebCore