Home | History | Annotate | Download | only in crypto
      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/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 WebCore {
     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     blink::WebCryptoAlgorithmId algorithmId;
     56 
     57 #if ASSERT_ENABLED
     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, blink::WebCryptoAlgorithmIdHmac},
     66     {"SHA-1", 5, blink::WebCryptoAlgorithmIdSha1},
     67     {"AES-KW", 6, blink::WebCryptoAlgorithmIdAesKw},
     68     {"SHA-512", 7, blink::WebCryptoAlgorithmIdSha512},
     69     {"SHA-384", 7, blink::WebCryptoAlgorithmIdSha384},
     70     {"SHA-256", 7, blink::WebCryptoAlgorithmIdSha256},
     71     {"AES-CBC", 7, blink::WebCryptoAlgorithmIdAesCbc},
     72     {"AES-GCM", 7, blink::WebCryptoAlgorithmIdAesGcm},
     73     {"AES-CTR", 7, blink::WebCryptoAlgorithmIdAesCtr},
     74     {"RSA-OAEP", 8, blink::WebCryptoAlgorithmIdRsaOaep},
     75     {"RSASSA-PKCS1-V1_5", 17, blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5},
     76 };
     77 
     78 #if ASSERT_ENABLED
     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, blink::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 = blink::WebCryptoErrorTypeSyntax;
    190     error->errorDetails = message;
    191 }
    192 
    193 void setNotSupportedError(const String& message, AlgorithmError* error)
    194 {
    195     error->errorType = blink::WebCryptoErrorTypeNotSupported;
    196     error->errorDetails = message;
    197 }
    198 
    199 void setDataError(const String& message, AlgorithmError* error)
    200 {
    201     error->errorType = blink::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 (!raw.get(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 (!raw.get(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 (!raw.get(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 = raw.get(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<blink::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 blink::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<blink::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 blink::WebCryptoAesKeyGenParams(length));
    440     return true;
    441 }
    442 
    443 bool parseAlgorithm(const Dictionary&, blink::WebCryptoOperation, blink::WebCryptoAlgorithm&, ErrorContext, AlgorithmError*);
    444 
    445 bool parseHash(const Dictionary& raw, blink::WebCryptoAlgorithm& hash, ErrorContext context, AlgorithmError* error)
    446 {
    447     Dictionary rawHash;
    448     if (!raw.get("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, blink::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<blink::WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
    463 {
    464     blink::WebCryptoAlgorithm hash;
    465     if (!parseHash(raw, hash, context, error))
    466         return false;
    467 
    468     params = adoptPtr(new blink::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<blink::WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
    482 {
    483     blink::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 blink::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<blink::WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
    502 {
    503     blink::WebCryptoAlgorithm hash;
    504     if (!parseHash(raw, hash, context, error))
    505         return false;
    506 
    507     params = adoptPtr(new blink::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<blink::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     blink::WebCryptoAlgorithm hash;
    532     if (!parseHash(raw, hash, context, error))
    533         return false;
    534 
    535     params = adoptPtr(new blink::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<blink::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 blink::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<blink::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 blink::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<blink::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 blink::WebCryptoRsaOaepParams(hasLabel, labelStart, labelLength));
    608     return true;
    609 }
    610 
    611 bool parseAlgorithmParams(const Dictionary& raw, blink::WebCryptoAlgorithmParamsType type, OwnPtr<blink::WebCryptoAlgorithmParams>& params, ErrorContext& context, AlgorithmError* error)
    612 {
    613     switch (type) {
    614     case blink::WebCryptoAlgorithmParamsTypeNone:
    615         return true;
    616     case blink::WebCryptoAlgorithmParamsTypeAesCbcParams:
    617         context.add("AesCbcParams");
    618         return parseAesCbcParams(raw, params, context, error);
    619     case blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams:
    620         context.add("AesKeyGenParams");
    621         return parseAesKeyGenParams(raw, params, context, error);
    622     case blink::WebCryptoAlgorithmParamsTypeHmacImportParams:
    623         context.add("HmacImportParams");
    624         return parseHmacImportParams(raw, params, context, error);
    625     case blink::WebCryptoAlgorithmParamsTypeHmacKeyGenParams:
    626         context.add("HmacKeyGenParams");
    627         return parseHmacKeyGenParams(raw, params, context, error);
    628     case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams:
    629         context.add("RsaHashedKeyGenParams");
    630         return parseRsaHashedKeyGenParams(raw, params, context, error);
    631     case blink::WebCryptoAlgorithmParamsTypeRsaHashedImportParams:
    632         context.add("RsaHashedImportParams");
    633         return parseRsaHashedImportParams(raw, params, context, error);
    634     case blink::WebCryptoAlgorithmParamsTypeAesCtrParams:
    635         context.add("AesCtrParams");
    636         return parseAesCtrParams(raw, params, context, error);
    637     case blink::WebCryptoAlgorithmParamsTypeAesGcmParams:
    638         context.add("AesGcmParams");
    639         return parseAesGcmParams(raw, params, context, error);
    640     case blink::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(blink::WebCryptoOperation op)
    650 {
    651     switch (op) {
    652     case blink::WebCryptoOperationEncrypt:
    653         return "encrypt";
    654     case blink::WebCryptoOperationDecrypt:
    655         return "decrypt";
    656     case blink::WebCryptoOperationSign:
    657         return "sign";
    658     case blink::WebCryptoOperationVerify:
    659         return "verify";
    660     case blink::WebCryptoOperationDigest:
    661         return "digest";
    662     case blink::WebCryptoOperationGenerateKey:
    663         return "generateKey";
    664     case blink::WebCryptoOperationImportKey:
    665         return "importKey";
    666     case blink::WebCryptoOperationDeriveKey:
    667         return "deriveKey";
    668     case blink::WebCryptoOperationDeriveBits:
    669         return "deriveBits";
    670     case blink::WebCryptoOperationWrapKey:
    671         return "wrapKey";
    672     case blink::WebCryptoOperationUnwrapKey:
    673         return "unwrapKey";
    674     }
    675     return 0;
    676 }
    677 
    678 bool parseAlgorithm(const Dictionary& raw, blink::WebCryptoOperation op, blink::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 (!raw.get("name", algorithmName)) {
    689         setSyntaxError(context.toString("name", "Missing or not a string"), error);
    690         return false;
    691     }
    692 
    693     blink::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 blink::WebCryptoAlgorithmInfo* algorithmInfo = blink::WebCryptoAlgorithm::lookupAlgorithmInfo(algorithmId);
    705 
    706     if (algorithmInfo->operationToParamsType[op] == blink::WebCryptoAlgorithmInfo::Undefined) {
    707         context.add(algorithmInfo->name);
    708         setNotSupportedError(context.toString("Unsupported operation", operationToString(op)), error);
    709         return false;
    710     }
    711 
    712     blink::WebCryptoAlgorithmParamsType paramsType = static_cast<blink::WebCryptoAlgorithmParamsType>(algorithmInfo->operationToParamsType[op]);
    713 
    714     OwnPtr<blink::WebCryptoAlgorithmParams> params;
    715     if (!parseAlgorithmParams(raw, paramsType, params, context, error))
    716         return false;
    717 
    718     algorithm = blink::WebCryptoAlgorithm(algorithmId, params.release());
    719     return true;
    720 }
    721 
    722 } // namespace
    723 
    724 bool normalizeAlgorithm(const Dictionary& raw, blink::WebCryptoOperation op, blink::WebCryptoAlgorithm& algorithm, AlgorithmError* error)
    725 {
    726     return parseAlgorithm(raw, op, algorithm, ErrorContext(), error);
    727 }
    728 
    729 } // namespace WebCore
    730