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 "bindings/v8/ExceptionState.h"
36#include "core/dom/ExceptionCode.h"
37#include "platform/NotImplemented.h"
38#include "public/platform/WebCryptoAlgorithmParams.h"
39#include "wtf/ArrayBuffer.h"
40#include "wtf/ArrayBufferView.h"
41#include "wtf/HashMap.h"
42#include "wtf/MathExtras.h"
43#include "wtf/Uint8Array.h"
44#include "wtf/Vector.h"
45#include "wtf/text/StringBuilder.h"
46#include "wtf/text/StringHash.h"
47
48namespace WebCore {
49
50namespace {
51
52struct AlgorithmNameMapping {
53    const char* const algorithmName;
54    blink::WebCryptoAlgorithmId algorithmId;
55};
56
57// Indicates that the algorithm doesn't support the specified operation.
58const int UnsupportedOp = -1;
59
60// Either UnsupportedOp, or a value from blink::WebCryptoAlgorithmParamsType
61typedef int AlgorithmParamsForOperation;
62
63struct OperationParamsMapping {
64    blink::WebCryptoAlgorithmId algorithmId;
65    AlgorithmOperation operation;
66    AlgorithmParamsForOperation params;
67};
68
69const AlgorithmNameMapping algorithmNameMappings[] = {
70    {"AES-CBC", blink::WebCryptoAlgorithmIdAesCbc},
71    {"AES-CTR", blink::WebCryptoAlgorithmIdAesCtr},
72    {"HMAC", blink::WebCryptoAlgorithmIdHmac},
73    {"RSASSA-PKCS1-v1_5", blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5},
74    {"RSAES-PKCS1-v1_5", blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5},
75    {"SHA-1", blink::WebCryptoAlgorithmIdSha1},
76    {"SHA-224", blink::WebCryptoAlgorithmIdSha224},
77    {"SHA-256", blink::WebCryptoAlgorithmIdSha256},
78    {"SHA-384", blink::WebCryptoAlgorithmIdSha384},
79    {"SHA-512", blink::WebCryptoAlgorithmIdSha512},
80    {"AES-KW", blink::WebCryptoAlgorithmIdAesKw},
81};
82
83// What operations each algorithm supports, and what parameters it expects.
84const OperationParamsMapping operationParamsMappings[] = {
85    // AES-CBC
86    {blink::WebCryptoAlgorithmIdAesCbc, Decrypt, blink::WebCryptoAlgorithmParamsTypeAesCbcParams},
87    {blink::WebCryptoAlgorithmIdAesCbc, Encrypt, blink::WebCryptoAlgorithmParamsTypeAesCbcParams},
88    {blink::WebCryptoAlgorithmIdAesCbc, GenerateKey, blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams},
89    {blink::WebCryptoAlgorithmIdAesCbc, ImportKey, blink::WebCryptoAlgorithmParamsTypeNone},
90    {blink::WebCryptoAlgorithmIdAesCbc, UnwrapKey, blink::WebCryptoAlgorithmParamsTypeAesCbcParams},
91    {blink::WebCryptoAlgorithmIdAesCbc, WrapKey, blink::WebCryptoAlgorithmParamsTypeAesCbcParams},
92
93    // AES-CTR
94    {blink::WebCryptoAlgorithmIdAesCtr, Decrypt, blink::WebCryptoAlgorithmParamsTypeAesCtrParams},
95    {blink::WebCryptoAlgorithmIdAesCtr, Encrypt, blink::WebCryptoAlgorithmParamsTypeAesCtrParams},
96    {blink::WebCryptoAlgorithmIdAesCtr, GenerateKey, blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams},
97    {blink::WebCryptoAlgorithmIdAesCtr, ImportKey, blink::WebCryptoAlgorithmParamsTypeNone},
98    {blink::WebCryptoAlgorithmIdAesCtr, UnwrapKey, blink::WebCryptoAlgorithmParamsTypeAesCtrParams},
99    {blink::WebCryptoAlgorithmIdAesCtr, WrapKey, blink::WebCryptoAlgorithmParamsTypeAesCtrParams},
100
101    // HMAC
102    {blink::WebCryptoAlgorithmIdHmac, Sign, blink::WebCryptoAlgorithmParamsTypeHmacParams},
103    {blink::WebCryptoAlgorithmIdHmac, Verify, blink::WebCryptoAlgorithmParamsTypeHmacParams},
104    {blink::WebCryptoAlgorithmIdHmac, GenerateKey, blink::WebCryptoAlgorithmParamsTypeHmacKeyParams},
105    {blink::WebCryptoAlgorithmIdHmac, ImportKey, blink::WebCryptoAlgorithmParamsTypeHmacParams},
106
107    // RSASSA-PKCS1-v1_5
108    {blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, Sign, blink::WebCryptoAlgorithmParamsTypeRsaSsaParams},
109    {blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, Verify, blink::WebCryptoAlgorithmParamsTypeRsaSsaParams},
110    {blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, GenerateKey, blink::WebCryptoAlgorithmParamsTypeRsaKeyGenParams},
111    {blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, ImportKey, blink::WebCryptoAlgorithmParamsTypeNone},
112
113    // RSAES-PKCS1-v1_5
114    {blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, Encrypt, blink::WebCryptoAlgorithmParamsTypeNone},
115    {blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, Decrypt, blink::WebCryptoAlgorithmParamsTypeNone},
116    {blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, GenerateKey, blink::WebCryptoAlgorithmParamsTypeRsaKeyGenParams},
117    {blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, ImportKey, blink::WebCryptoAlgorithmParamsTypeNone},
118    {blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, WrapKey, blink::WebCryptoAlgorithmParamsTypeNone},
119    {blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, UnwrapKey, blink::WebCryptoAlgorithmParamsTypeNone},
120
121    // SHA-*
122    {blink::WebCryptoAlgorithmIdSha1, Digest, blink::WebCryptoAlgorithmParamsTypeNone},
123    {blink::WebCryptoAlgorithmIdSha224, Digest, blink::WebCryptoAlgorithmParamsTypeNone},
124    {blink::WebCryptoAlgorithmIdSha256, Digest, blink::WebCryptoAlgorithmParamsTypeNone},
125    {blink::WebCryptoAlgorithmIdSha384, Digest, blink::WebCryptoAlgorithmParamsTypeNone},
126    {blink::WebCryptoAlgorithmIdSha512, Digest, blink::WebCryptoAlgorithmParamsTypeNone},
127
128    // AES-KW
129    {blink::WebCryptoAlgorithmIdAesKw, GenerateKey, blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams},
130    {blink::WebCryptoAlgorithmIdAesKw, ImportKey, blink::WebCryptoAlgorithmParamsTypeNone},
131    {blink::WebCryptoAlgorithmIdAesKw, UnwrapKey, blink::WebCryptoAlgorithmParamsTypeNone},
132    {blink::WebCryptoAlgorithmIdAesKw, WrapKey, blink::WebCryptoAlgorithmParamsTypeNone},
133};
134
135// This structure describes an algorithm and its supported operations.
136struct AlgorithmInfo {
137    AlgorithmInfo()
138        : algorithmName(0)
139    {
140        for (size_t i = 0; i < WTF_ARRAY_LENGTH(paramsForOperation); ++i)
141            paramsForOperation[i] = UnsupportedOp;
142    }
143
144    blink::WebCryptoAlgorithmId algorithmId;
145    const char* algorithmName;
146    AlgorithmParamsForOperation paramsForOperation[LastAlgorithmOperation + 1];
147};
148
149// AlgorithmRegistry enumerates each of the different algorithms and its
150// parameters. This describes the same information as the static tables above,
151// but in a more convenient runtime form.
152class AlgorithmRegistry {
153public:
154    static AlgorithmRegistry& instance();
155
156    const AlgorithmInfo* lookupAlgorithmByName(const String&) const;
157    const AlgorithmInfo* lookupAlgorithmById(blink::WebCryptoAlgorithmId) const;
158
159private:
160    AlgorithmRegistry();
161
162    // Algorithm name to ID.
163    typedef HashMap<String, blink::WebCryptoAlgorithmId, CaseFoldingHash> AlgorithmNameToIdMap;
164    AlgorithmNameToIdMap m_algorithmNameToId;
165
166    // Algorithm ID to information.
167    AlgorithmInfo m_algorithms[blink::NumberOfWebCryptoAlgorithmId];
168};
169
170AlgorithmRegistry& AlgorithmRegistry::instance()
171{
172    DEFINE_STATIC_LOCAL(AlgorithmRegistry, registry, ());
173    return registry;
174}
175
176const AlgorithmInfo* AlgorithmRegistry::lookupAlgorithmByName(const String& algorithmName) const
177{
178    AlgorithmNameToIdMap::const_iterator it = m_algorithmNameToId.find(algorithmName);
179    if (it == m_algorithmNameToId.end())
180        return 0;
181    return lookupAlgorithmById(it->value);
182}
183
184const AlgorithmInfo* AlgorithmRegistry::lookupAlgorithmById(blink::WebCryptoAlgorithmId algorithmId) const
185{
186    ASSERT(algorithmId >= 0 && algorithmId < WTF_ARRAY_LENGTH(m_algorithms));
187    return &m_algorithms[algorithmId];
188}
189
190AlgorithmRegistry::AlgorithmRegistry()
191{
192    for (size_t i = 0; i < WTF_ARRAY_LENGTH(algorithmNameMappings); ++i) {
193        const AlgorithmNameMapping& mapping = algorithmNameMappings[i];
194        m_algorithmNameToId.add(mapping.algorithmName, mapping.algorithmId);
195        m_algorithms[mapping.algorithmId].algorithmName = mapping.algorithmName;
196        m_algorithms[mapping.algorithmId].algorithmId = mapping.algorithmId;
197    }
198
199    for (size_t i = 0; i < WTF_ARRAY_LENGTH(operationParamsMappings); ++i) {
200        const OperationParamsMapping& mapping = operationParamsMappings[i];
201        m_algorithms[mapping.algorithmId].paramsForOperation[mapping.operation] = mapping.params;
202    }
203}
204
205// ExceptionContext holds a stack of string literals which describe what was
206// happening at the time the exception was thrown. This is helpful because
207// parsing of the algorithm dictionary can be recursive and it is difficult to
208// tell what went wrong from the exception type alone (TypeError).
209class ExceptionContext {
210public:
211    explicit ExceptionContext(AlgorithmOperation op)
212        : m_op(op)
213    {
214    }
215
216    void add(const char* message)
217    {
218        m_messages.append(message);
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        ExceptionContext stack(*this);
247        stack.add(message);
248        return stack.toString();
249    }
250
251    String toString(const char* message1, const char* message2) const
252    {
253        ExceptionContext stack(*this);
254        stack.add(message1);
255        stack.add(message2);
256        return stack.toString();
257    }
258
259private:
260    AlgorithmOperation m_op;
261
262    // This inline size is large enough to avoid having to grow the Vector in
263    // the majority of cases (up to 1 nested algorithm identifier).
264    Vector<const char*, 10> m_messages;
265};
266
267bool getArrayBufferView(const Dictionary& raw, const char* propertyName, RefPtr<ArrayBufferView>& buffer, const ExceptionContext& context, ExceptionState& exceptionState)
268{
269    if (!raw.get(propertyName, buffer) || !buffer) {
270        exceptionState.throwTypeError(context.toString(propertyName, "Missing or not a ArrayBufferView"));
271        return false;
272    }
273    return true;
274}
275
276bool getUint8Array(const Dictionary& raw, const char* propertyName, RefPtr<Uint8Array>& array, const ExceptionContext& context, ExceptionState& exceptionState)
277{
278    if (!raw.get(propertyName, array) || !array) {
279        exceptionState.throwTypeError(context.toString(propertyName, "Missing or not a Uint8Array"));
280        return false;
281    }
282    return true;
283}
284
285// Gets an integer according to WebIDL's [EnforceRange].
286bool getOptionalInteger(const Dictionary& raw, const char* propertyName, bool& hasProperty, double& value, double minValue, double maxValue, const ExceptionContext& context, ExceptionState& exceptionState)
287{
288    double number;
289    bool ok = raw.get(propertyName, number, hasProperty);
290
291    if (!hasProperty)
292        return true;
293
294    if (!ok || std::isnan(number)) {
295        exceptionState.throwTypeError(context.toString(propertyName, "Is not a number"));
296        return false;
297    }
298
299    number = trunc(number);
300
301    if (std::isinf(number) || number < minValue || number > maxValue) {
302        exceptionState.throwTypeError(context.toString(propertyName, "Outside of numeric range"));
303        return false;
304    }
305
306    value = number;
307    return true;
308}
309
310bool getInteger(const Dictionary& raw, const char* propertyName, double& value, double minValue, double maxValue, const ExceptionContext& context, ExceptionState& exceptionState)
311{
312    bool hasProperty;
313    if (!getOptionalInteger(raw, propertyName, hasProperty, value, minValue, maxValue, context, exceptionState))
314        return false;
315
316    if (!hasProperty) {
317        exceptionState.throwTypeError(context.toString(propertyName, "Missing required property"));
318        return false;
319    }
320
321    return true;
322}
323
324bool getUint32(const Dictionary& raw, const char* propertyName, uint32_t& value, const ExceptionContext& context, ExceptionState& exceptionState)
325{
326    double number;
327    if (!getInteger(raw, propertyName, number, 0, 0xFFFFFFFF, context, exceptionState))
328        return false;
329    value = number;
330    return true;
331}
332
333bool getUint16(const Dictionary& raw, const char* propertyName, uint16_t& value, const ExceptionContext& context, ExceptionState& exceptionState)
334{
335    double number;
336    if (!getInteger(raw, propertyName, number, 0, 0xFFFF, context, exceptionState))
337        return false;
338    value = number;
339    return true;
340}
341
342bool getUint8(const Dictionary& raw, const char* propertyName, uint8_t& value, const ExceptionContext& context, ExceptionState& exceptionState)
343{
344    double number;
345    if (!getInteger(raw, propertyName, number, 0, 0xFF, context, exceptionState))
346        return false;
347    value = number;
348    return true;
349}
350
351bool getOptionalUint32(const Dictionary& raw, const char* propertyName, bool& hasValue, uint32_t& value, const ExceptionContext& context, ExceptionState& exceptionState)
352{
353    double number;
354    if (!getOptionalInteger(raw, propertyName, hasValue, number, 0, 0xFFFFFFFF, context, exceptionState))
355        return false;
356    if (hasValue)
357        value = number;
358    return true;
359}
360
361bool parseAesCbcParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ExceptionContext& context, ExceptionState& exceptionState)
362{
363    RefPtr<ArrayBufferView> iv;
364    if (!getArrayBufferView(raw, "iv", iv, context, exceptionState))
365        return false;
366
367    if (iv->byteLength() != 16) {
368        exceptionState.throwTypeError(context.toString("iv", "Must be 16 bytes"));
369        return false;
370    }
371
372    params = adoptPtr(new blink::WebCryptoAesCbcParams(static_cast<unsigned char*>(iv->baseAddress()), iv->byteLength()));
373    return true;
374}
375
376bool parseAesKeyGenParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ExceptionContext& context, ExceptionState& exceptionState)
377{
378    uint16_t length;
379    if (!getUint16(raw, "length", length, context, exceptionState))
380        return false;
381
382    params = adoptPtr(new blink::WebCryptoAesKeyGenParams(length));
383    return true;
384}
385
386bool normalizeAlgorithm(const Dictionary&, AlgorithmOperation, blink::WebCryptoAlgorithm&, ExceptionContext, ExceptionState&);
387
388bool parseHash(const Dictionary& raw, blink::WebCryptoAlgorithm& hash, ExceptionContext context, ExceptionState& exceptionState)
389{
390    Dictionary rawHash;
391    if (!raw.get("hash", rawHash)) {
392        exceptionState.throwTypeError(context.toString("hash", "Missing or not a dictionary"));
393        return false;
394    }
395
396    context.add("hash");
397    return normalizeAlgorithm(rawHash, Digest, hash, context, exceptionState);
398}
399
400bool parseHmacParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ExceptionContext& context, ExceptionState& exceptionState)
401{
402    blink::WebCryptoAlgorithm hash;
403    if (!parseHash(raw, hash, context, exceptionState))
404        return false;
405
406    params = adoptPtr(new blink::WebCryptoHmacParams(hash));
407    return true;
408}
409
410bool parseHmacKeyParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ExceptionContext& context, ExceptionState& exceptionState)
411{
412    blink::WebCryptoAlgorithm hash;
413    if (!parseHash(raw, hash, context, exceptionState))
414        return false;
415
416    bool hasLength;
417    uint32_t length = 0;
418    if (!getOptionalUint32(raw, "length", hasLength, length, context, exceptionState))
419        return false;
420
421    params = adoptPtr(new blink::WebCryptoHmacKeyParams(hash, hasLength, length));
422    return true;
423}
424
425bool parseRsaSsaParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ExceptionContext& context, ExceptionState& exceptionState)
426{
427    blink::WebCryptoAlgorithm hash;
428    if (!parseHash(raw, hash, context, exceptionState))
429        return false;
430
431    params = adoptPtr(new blink::WebCryptoRsaSsaParams(hash));
432    return true;
433}
434
435bool parseRsaKeyGenParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ExceptionContext& context, ExceptionState& exceptionState)
436{
437    uint32_t modulusLength;
438    if (!getUint32(raw, "modulusLength", modulusLength, context, exceptionState))
439        return false;
440
441    RefPtr<Uint8Array> publicExponent;
442    if (!getUint8Array(raw, "publicExponent", publicExponent, context, exceptionState))
443        return false;
444
445    params = adoptPtr(new blink::WebCryptoRsaKeyGenParams(modulusLength, static_cast<const unsigned char*>(publicExponent->baseAddress()), publicExponent->byteLength()));
446    return true;
447}
448
449bool parseAesCtrParams(const Dictionary& raw, OwnPtr<blink::WebCryptoAlgorithmParams>& params, const ExceptionContext& context, ExceptionState& es)
450{
451    RefPtr<Uint8Array> counter;
452    if (!getUint8Array(raw, "counter", counter, context, es))
453        return false;
454
455    uint8_t length;
456    if (!getUint8(raw, "length", length, context, es))
457        return false;
458
459    params = adoptPtr(new blink::WebCryptoAesCtrParams(length, static_cast<const unsigned char*>(counter->baseAddress()), counter->byteLength()));
460    return true;
461}
462
463bool parseAlgorithmParams(const Dictionary& raw, blink::WebCryptoAlgorithmParamsType type, OwnPtr<blink::WebCryptoAlgorithmParams>& params, ExceptionContext& context, ExceptionState& exceptionState)
464{
465    switch (type) {
466    case blink::WebCryptoAlgorithmParamsTypeNone:
467        return true;
468    case blink::WebCryptoAlgorithmParamsTypeAesCbcParams:
469        context.add("AesCbcParams");
470        return parseAesCbcParams(raw, params, context, exceptionState);
471    case blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams:
472        context.add("AesKeyGenParams");
473        return parseAesKeyGenParams(raw, params, context, exceptionState);
474    case blink::WebCryptoAlgorithmParamsTypeHmacParams:
475        context.add("HmacParams");
476        return parseHmacParams(raw, params, context, exceptionState);
477    case blink::WebCryptoAlgorithmParamsTypeHmacKeyParams:
478        context.add("HmacKeyParams");
479        return parseHmacKeyParams(raw, params, context, exceptionState);
480    case blink::WebCryptoAlgorithmParamsTypeRsaSsaParams:
481        context.add("RsaSSaParams");
482        return parseRsaSsaParams(raw, params, context, exceptionState);
483    case blink::WebCryptoAlgorithmParamsTypeRsaKeyGenParams:
484        context.add("RsaKeyGenParams");
485        return parseRsaKeyGenParams(raw, params, context, exceptionState);
486    case blink::WebCryptoAlgorithmParamsTypeAesCtrParams:
487        context.add("AesCtrParams");
488        return parseAesCtrParams(raw, params, context, exceptionState);
489    case blink::WebCryptoAlgorithmParamsTypeAesGcmParams:
490    case blink::WebCryptoAlgorithmParamsTypeRsaOaepParams:
491        // TODO
492        notImplemented();
493        break;
494    }
495    ASSERT_NOT_REACHED();
496    return false;
497}
498
499const AlgorithmInfo* algorithmInfo(const Dictionary& raw, const ExceptionContext& context, ExceptionState& exceptionState)
500{
501    if (!raw.isObject()) {
502        exceptionState.throwTypeError(context.toString("Not an object"));
503        return 0;
504    }
505
506    String algorithmName;
507    if (!raw.get("name", algorithmName)) {
508        exceptionState.throwTypeError(context.toString("name", "Missing or not a string"));
509        return 0;
510    }
511
512    const AlgorithmInfo* info = AlgorithmRegistry::instance().lookupAlgorithmByName(algorithmName);
513    if (!info) {
514        exceptionState.throwDOMException(NotSupportedError, context.toString("Unrecognized algorithm name"));
515        return 0;
516    }
517
518    return info;
519}
520
521// This implementation corresponds with:
522// http://www.w3.org/TR/WebCryptoAPI/#algorithm-normalizing-rules
523bool normalizeAlgorithm(const Dictionary& raw, AlgorithmOperation op, blink::WebCryptoAlgorithm& algorithm, ExceptionContext context, ExceptionState& exceptionState)
524{
525    context.add("Algorithm");
526
527    const AlgorithmInfo* info = algorithmInfo(raw, context, exceptionState);
528    if (!info)
529        return false;
530
531    context.add(info->algorithmName);
532
533    if (info->paramsForOperation[op] == UnsupportedOp) {
534        exceptionState.throwDOMException(NotSupportedError, context.toString("Unsupported operation"));
535        return false;
536    }
537
538    blink::WebCryptoAlgorithmParamsType paramsType = static_cast<blink::WebCryptoAlgorithmParamsType>(info->paramsForOperation[op]);
539    OwnPtr<blink::WebCryptoAlgorithmParams> params;
540    if (!parseAlgorithmParams(raw, paramsType, params, context, exceptionState))
541        return false;
542
543    algorithm = blink::WebCryptoAlgorithm(info->algorithmId, params.release());
544    return true;
545}
546
547} // namespace
548
549bool normalizeAlgorithm(const Dictionary& raw, AlgorithmOperation op, blink::WebCryptoAlgorithm& algorithm, ExceptionState& exceptionState)
550{
551    return normalizeAlgorithm(raw, op, algorithm, ExceptionContext(op), exceptionState);
552}
553
554const char* algorithmIdToName(blink::WebCryptoAlgorithmId id)
555{
556    return AlgorithmRegistry::instance().lookupAlgorithmById(id)->algorithmName;
557}
558
559} // namespace WebCore
560