| /* |
| * Copyright (C) 2013 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "modules/crypto/NormalizeAlgorithm.h" |
| |
| #include "bindings/core/v8/ArrayBufferOrArrayBufferView.h" |
| #include "bindings/core/v8/Dictionary.h" |
| #include "bindings/core/v8/V8ArrayBuffer.h" |
| #include "bindings/core/v8/V8ArrayBufferView.h" |
| #include "bindings/modules/v8/V8CryptoKey.h" |
| #include "core/dom/DOMArrayPiece.h" |
| #include "core/dom/DOMTypedArray.h" |
| #include "public/platform/WebCryptoAlgorithmParams.h" |
| #include "public/platform/WebString.h" |
| #include "wtf/MathExtras.h" |
| #include "wtf/PtrUtil.h" |
| #include "wtf/Vector.h" |
| #include "wtf/text/StringBuilder.h" |
| #include <algorithm> |
| #include <memory> |
| |
| namespace blink { |
| |
| namespace { |
| |
| typedef ArrayBufferOrArrayBufferView BufferSource; |
| |
| struct AlgorithmNameMapping { |
| // Must be an upper case ASCII string. |
| const char* const algorithm_name; |
| // Must be strlen(algorithmName). |
| unsigned char algorithm_name_length; |
| WebCryptoAlgorithmId algorithm_id; |
| |
| #if DCHECK_IS_ON() |
| bool operator<(const AlgorithmNameMapping&) const; |
| #endif |
| }; |
| |
| // Must be sorted by length, and then by reverse string. |
| // Also all names must be upper case ASCII. |
| const AlgorithmNameMapping kAlgorithmNameMappings[] = { |
| {"HMAC", 4, kWebCryptoAlgorithmIdHmac}, |
| {"HKDF", 4, kWebCryptoAlgorithmIdHkdf}, |
| {"ECDH", 4, kWebCryptoAlgorithmIdEcdh}, |
| {"SHA-1", 5, kWebCryptoAlgorithmIdSha1}, |
| {"ECDSA", 5, kWebCryptoAlgorithmIdEcdsa}, |
| {"PBKDF2", 6, kWebCryptoAlgorithmIdPbkdf2}, |
| {"AES-KW", 6, kWebCryptoAlgorithmIdAesKw}, |
| {"SHA-512", 7, kWebCryptoAlgorithmIdSha512}, |
| {"SHA-384", 7, kWebCryptoAlgorithmIdSha384}, |
| {"SHA-256", 7, kWebCryptoAlgorithmIdSha256}, |
| {"AES-CBC", 7, kWebCryptoAlgorithmIdAesCbc}, |
| {"AES-GCM", 7, kWebCryptoAlgorithmIdAesGcm}, |
| {"AES-CTR", 7, kWebCryptoAlgorithmIdAesCtr}, |
| {"RSA-PSS", 7, kWebCryptoAlgorithmIdRsaPss}, |
| {"RSA-OAEP", 8, kWebCryptoAlgorithmIdRsaOaep}, |
| {"RSASSA-PKCS1-V1_5", 17, kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5}, |
| }; |
| |
| // Reminder to update the table mapping names to IDs whenever adding a new |
| // algorithm ID. |
| static_assert(kWebCryptoAlgorithmIdLast + 1 == |
| WTF_ARRAY_LENGTH(kAlgorithmNameMappings), |
| "algorithmNameMappings needs to be updated"); |
| |
| #if DCHECK_IS_ON() |
| |
| // Essentially std::is_sorted() (however that function is new to C++11). |
| template <typename Iterator> |
| bool IsSorted(Iterator begin, Iterator end) { |
| if (begin == end) |
| return true; |
| |
| Iterator prev = begin; |
| Iterator cur = begin + 1; |
| |
| while (cur != end) { |
| if (*cur < *prev) |
| return false; |
| cur++; |
| prev++; |
| } |
| |
| return true; |
| } |
| |
| bool AlgorithmNameMapping::operator<(const AlgorithmNameMapping& o) const { |
| if (algorithm_name_length < o.algorithm_name_length) |
| return true; |
| if (algorithm_name_length > o.algorithm_name_length) |
| return false; |
| |
| for (size_t i = 0; i < algorithm_name_length; ++i) { |
| size_t reverse_index = algorithm_name_length - i - 1; |
| char c1 = algorithm_name[reverse_index]; |
| char c2 = o.algorithm_name[reverse_index]; |
| |
| if (c1 < c2) |
| return true; |
| if (c1 > c2) |
| return false; |
| } |
| |
| return false; |
| } |
| |
| bool VerifyAlgorithmNameMappings(const AlgorithmNameMapping* begin, |
| const AlgorithmNameMapping* end) { |
| for (const AlgorithmNameMapping* it = begin; it != end; ++it) { |
| if (it->algorithm_name_length != strlen(it->algorithm_name)) |
| return false; |
| String str(it->algorithm_name, it->algorithm_name_length); |
| if (!str.ContainsOnlyASCII()) |
| return false; |
| if (str.DeprecatedUpper() != str) |
| return false; |
| } |
| |
| return IsSorted(begin, end); |
| } |
| #endif |
| |
| template <typename CharType> |
| bool AlgorithmNameComparator(const AlgorithmNameMapping& a, StringImpl* b) { |
| if (a.algorithm_name_length < b->length()) |
| return true; |
| if (a.algorithm_name_length > b->length()) |
| return false; |
| |
| // Because the algorithm names contain many common prefixes, it is better |
| // to compare starting at the end of the string. |
| for (size_t i = 0; i < a.algorithm_name_length; ++i) { |
| size_t reverse_index = a.algorithm_name_length - i - 1; |
| CharType c1 = a.algorithm_name[reverse_index]; |
| CharType c2 = b->GetCharacters<CharType>()[reverse_index]; |
| if (!IsASCII(c2)) |
| return false; |
| c2 = ToASCIIUpper(c2); |
| |
| if (c1 < c2) |
| return true; |
| if (c1 > c2) |
| return false; |
| } |
| |
| return false; |
| } |
| |
| bool LookupAlgorithmIdByName(const String& algorithm_name, |
| WebCryptoAlgorithmId& id) { |
| const AlgorithmNameMapping* begin = kAlgorithmNameMappings; |
| const AlgorithmNameMapping* end = |
| kAlgorithmNameMappings + WTF_ARRAY_LENGTH(kAlgorithmNameMappings); |
| |
| ASSERT(VerifyAlgorithmNameMappings(begin, end)); |
| |
| const AlgorithmNameMapping* it; |
| if (algorithm_name.Impl()->Is8Bit()) |
| it = std::lower_bound(begin, end, algorithm_name.Impl(), |
| &AlgorithmNameComparator<LChar>); |
| else |
| it = std::lower_bound(begin, end, algorithm_name.Impl(), |
| &AlgorithmNameComparator<UChar>); |
| |
| if (it == end) |
| return false; |
| |
| if (it->algorithm_name_length != algorithm_name.length() || |
| !DeprecatedEqualIgnoringCase(algorithm_name, it->algorithm_name)) |
| return false; |
| |
| id = it->algorithm_id; |
| return true; |
| } |
| |
| void SetTypeError(const String& message, AlgorithmError* error) { |
| error->error_type = kWebCryptoErrorTypeType; |
| error->error_details = message; |
| } |
| |
| void SetNotSupportedError(const String& message, AlgorithmError* error) { |
| error->error_type = kWebCryptoErrorTypeNotSupported; |
| error->error_details = message; |
| } |
| |
| // ErrorContext holds a stack of string literals which describe what was |
| // happening at the time the error occurred. This is helpful because |
| // parsing of the algorithm dictionary can be recursive and it is difficult to |
| // tell what went wrong from a failure alone. |
| class ErrorContext { |
| public: |
| void Add(const char* message) { messages_.push_back(message); } |
| |
| void RemoveLast() { messages_.pop_back(); } |
| |
| // Join all of the string literals into a single String. |
| String ToString() const { |
| if (messages_.IsEmpty()) |
| return String(); |
| |
| StringBuilder result; |
| const char* separator = ": "; |
| |
| size_t length = (messages_.size() - 1) * strlen(separator); |
| for (size_t i = 0; i < messages_.size(); ++i) |
| length += strlen(messages_[i]); |
| result.ReserveCapacity(length); |
| |
| for (size_t i = 0; i < messages_.size(); ++i) { |
| if (i) |
| result.Append(separator, strlen(separator)); |
| result.Append(messages_[i], strlen(messages_[i])); |
| } |
| |
| return result.ToString(); |
| } |
| |
| String ToString(const char* message) const { |
| ErrorContext stack(*this); |
| stack.Add(message); |
| return stack.ToString(); |
| } |
| |
| String ToString(const char* message1, const char* message2) const { |
| ErrorContext stack(*this); |
| stack.Add(message1); |
| stack.Add(message2); |
| return stack.ToString(); |
| } |
| |
| private: |
| // This inline size is large enough to avoid having to grow the Vector in |
| // the majority of cases (up to 1 nested algorithm identifier). |
| Vector<const char*, 10> messages_; |
| }; |
| |
| static WebVector<uint8_t> CopyBytes(const DOMArrayPiece& source) { |
| return WebVector<uint8_t>(static_cast<const uint8_t*>(source.Data()), |
| source.ByteLength()); |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // typedef (ArrayBuffer or ArrayBufferView) BufferSource; |
| // |
| bool GetOptionalBufferSource(const Dictionary& raw, |
| const char* property_name, |
| bool& has_property, |
| WebVector<uint8_t>& bytes, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| has_property = false; |
| v8::Local<v8::Value> v8_value; |
| if (!raw.Get(property_name, v8_value)) |
| return true; |
| has_property = true; |
| |
| if (v8_value->IsArrayBufferView()) { |
| bytes = CopyBytes( |
| V8ArrayBufferView::toImpl(v8::Local<v8::Object>::Cast(v8_value))); |
| return true; |
| } |
| |
| if (v8_value->IsArrayBuffer()) { |
| bytes = |
| CopyBytes(V8ArrayBuffer::toImpl(v8::Local<v8::Object>::Cast(v8_value))); |
| return true; |
| } |
| |
| if (has_property) { |
| SetTypeError(context.ToString(property_name, "Not a BufferSource"), error); |
| return false; |
| } |
| return true; |
| } |
| |
| bool GetBufferSource(const Dictionary& raw, |
| const char* property_name, |
| WebVector<uint8_t>& bytes, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| bool has_property; |
| bool ok = GetOptionalBufferSource(raw, property_name, has_property, bytes, |
| context, error); |
| if (!has_property) { |
| SetTypeError(context.ToString(property_name, "Missing required property"), |
| error); |
| return false; |
| } |
| return ok; |
| } |
| |
| bool GetUint8Array(const Dictionary& raw, |
| const char* property_name, |
| WebVector<uint8_t>& bytes, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| DOMUint8Array* array = nullptr; |
| if (!DictionaryHelper::Get(raw, property_name, array) || !array) { |
| SetTypeError(context.ToString(property_name, "Missing or not a Uint8Array"), |
| error); |
| return false; |
| } |
| bytes = CopyBytes(array); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // typedef Uint8Array BigInteger; |
| bool GetBigInteger(const Dictionary& raw, |
| const char* property_name, |
| WebVector<uint8_t>& bytes, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| if (!GetUint8Array(raw, property_name, bytes, context, error)) |
| return false; |
| |
| if (bytes.IsEmpty()) { |
| // Empty BigIntegers represent 0 according to the spec |
| bytes = WebVector<uint8_t>(static_cast<size_t>(1u)); |
| DCHECK_EQ(0u, bytes[0]); |
| } |
| |
| return true; |
| } |
| |
| // Gets an integer according to WebIDL's [EnforceRange]. |
| bool GetOptionalInteger(const Dictionary& raw, |
| const char* property_name, |
| bool& has_property, |
| double& value, |
| double min_value, |
| double max_value, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| double number; |
| bool ok = DictionaryHelper::Get(raw, property_name, number, has_property); |
| |
| if (!has_property) |
| return true; |
| |
| if (!ok || std::isnan(number)) { |
| SetTypeError(context.ToString(property_name, "Is not a number"), error); |
| return false; |
| } |
| |
| number = trunc(number); |
| |
| if (std::isinf(number) || number < min_value || number > max_value) { |
| SetTypeError(context.ToString(property_name, "Outside of numeric range"), |
| error); |
| return false; |
| } |
| |
| value = number; |
| return true; |
| } |
| |
| bool GetInteger(const Dictionary& raw, |
| const char* property_name, |
| double& value, |
| double min_value, |
| double max_value, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| bool has_property; |
| if (!GetOptionalInteger(raw, property_name, has_property, value, min_value, |
| max_value, context, error)) |
| return false; |
| |
| if (!has_property) { |
| SetTypeError(context.ToString(property_name, "Missing required property"), |
| error); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool GetUint32(const Dictionary& raw, |
| const char* property_name, |
| uint32_t& value, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| double number; |
| if (!GetInteger(raw, property_name, number, 0, 0xFFFFFFFF, context, error)) |
| return false; |
| value = number; |
| return true; |
| } |
| |
| bool GetUint16(const Dictionary& raw, |
| const char* property_name, |
| uint16_t& value, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| double number; |
| if (!GetInteger(raw, property_name, number, 0, 0xFFFF, context, error)) |
| return false; |
| value = number; |
| return true; |
| } |
| |
| bool GetUint8(const Dictionary& raw, |
| const char* property_name, |
| uint8_t& value, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| double number; |
| if (!GetInteger(raw, property_name, number, 0, 0xFF, context, error)) |
| return false; |
| value = number; |
| return true; |
| } |
| |
| bool GetOptionalUint32(const Dictionary& raw, |
| const char* property_name, |
| bool& has_value, |
| uint32_t& value, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| double number; |
| if (!GetOptionalInteger(raw, property_name, has_value, number, 0, 0xFFFFFFFF, |
| context, error)) |
| return false; |
| if (has_value) |
| value = number; |
| return true; |
| } |
| |
| bool GetOptionalUint8(const Dictionary& raw, |
| const char* property_name, |
| bool& has_value, |
| uint8_t& value, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| double number; |
| if (!GetOptionalInteger(raw, property_name, has_value, number, 0, 0xFF, |
| context, error)) |
| return false; |
| if (has_value) |
| value = number; |
| return true; |
| } |
| |
| bool GetAlgorithmIdentifier(const Dictionary& raw, |
| const char* property_name, |
| AlgorithmIdentifier& value, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| // FIXME: This is not correct: http://crbug.com/438060 |
| // (1) It may retrieve the property twice from the dictionary, whereas it |
| // should be reading the v8 value once to avoid issues with getters. |
| // (2) The value is stringified (whereas the spec says it should be an |
| // instance of DOMString). |
| Dictionary dictionary; |
| if (DictionaryHelper::Get(raw, property_name, dictionary) && |
| !dictionary.IsUndefinedOrNull()) { |
| value.setDictionary(dictionary); |
| return true; |
| } |
| |
| String algorithm_name; |
| if (!DictionaryHelper::Get(raw, property_name, algorithm_name)) { |
| SetTypeError(context.ToString(property_name, |
| "Missing or not an AlgorithmIdentifier"), |
| error); |
| return false; |
| } |
| |
| value.setString(algorithm_name); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary AesCbcParams : Algorithm { |
| // required BufferSource iv; |
| // }; |
| bool ParseAesCbcParams(const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| WebVector<uint8_t> iv; |
| if (!GetBufferSource(raw, "iv", iv, context, error)) |
| return false; |
| |
| params = WTF::WrapUnique(new WebCryptoAesCbcParams(std::move(iv))); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary AesKeyGenParams : Algorithm { |
| // [EnforceRange] required unsigned short length; |
| // }; |
| bool ParseAesKeyGenParams(const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| uint16_t length; |
| if (!GetUint16(raw, "length", length, context, error)) |
| return false; |
| |
| params = WTF::MakeUnique<WebCryptoAesKeyGenParams>(length); |
| return true; |
| } |
| |
| bool ParseAlgorithmIdentifier(const AlgorithmIdentifier&, |
| WebCryptoOperation, |
| WebCryptoAlgorithm&, |
| ErrorContext, |
| AlgorithmError*); |
| |
| bool ParseHash(const Dictionary& raw, |
| WebCryptoAlgorithm& hash, |
| ErrorContext context, |
| AlgorithmError* error) { |
| AlgorithmIdentifier raw_hash; |
| if (!GetAlgorithmIdentifier(raw, "hash", raw_hash, context, error)) |
| return false; |
| |
| context.Add("hash"); |
| return ParseAlgorithmIdentifier(raw_hash, kWebCryptoOperationDigest, hash, |
| context, error); |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary HmacImportParams : Algorithm { |
| // required HashAlgorithmIdentifier hash; |
| // [EnforceRange] unsigned long length; |
| // }; |
| bool ParseHmacImportParams(const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| WebCryptoAlgorithm hash; |
| if (!ParseHash(raw, hash, context, error)) |
| return false; |
| |
| bool has_length; |
| uint32_t length = 0; |
| if (!GetOptionalUint32(raw, "length", has_length, length, context, error)) |
| return false; |
| |
| params = WTF::MakeUnique<WebCryptoHmacImportParams>(hash, has_length, length); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary HmacKeyGenParams : Algorithm { |
| // required HashAlgorithmIdentifier hash; |
| // [EnforceRange] unsigned long length; |
| // }; |
| bool ParseHmacKeyGenParams(const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| WebCryptoAlgorithm hash; |
| if (!ParseHash(raw, hash, context, error)) |
| return false; |
| |
| bool has_length; |
| uint32_t length = 0; |
| if (!GetOptionalUint32(raw, "length", has_length, length, context, error)) |
| return false; |
| |
| params = WTF::MakeUnique<WebCryptoHmacKeyGenParams>(hash, has_length, length); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary RsaHashedImportParams : Algorithm { |
| // required HashAlgorithmIdentifier hash; |
| // }; |
| bool ParseRsaHashedImportParams( |
| const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| WebCryptoAlgorithm hash; |
| if (!ParseHash(raw, hash, context, error)) |
| return false; |
| |
| params = WTF::MakeUnique<WebCryptoRsaHashedImportParams>(hash); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary RsaKeyGenParams : Algorithm { |
| // [EnforceRange] required unsigned long modulusLength; |
| // required BigInteger publicExponent; |
| // }; |
| // |
| // dictionary RsaHashedKeyGenParams : RsaKeyGenParams { |
| // required HashAlgorithmIdentifier hash; |
| // }; |
| bool ParseRsaHashedKeyGenParams( |
| const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| uint32_t modulus_length; |
| if (!GetUint32(raw, "modulusLength", modulus_length, context, error)) |
| return false; |
| |
| WebVector<uint8_t> public_exponent; |
| if (!GetBigInteger(raw, "publicExponent", public_exponent, context, error)) |
| return false; |
| |
| WebCryptoAlgorithm hash; |
| if (!ParseHash(raw, hash, context, error)) |
| return false; |
| |
| params = WTF::WrapUnique(new WebCryptoRsaHashedKeyGenParams( |
| hash, modulus_length, std::move(public_exponent))); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary AesCtrParams : Algorithm { |
| // required BufferSource counter; |
| // [EnforceRange] required octet length; |
| // }; |
| bool ParseAesCtrParams(const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| WebVector<uint8_t> counter; |
| if (!GetBufferSource(raw, "counter", counter, context, error)) |
| return false; |
| |
| uint8_t length; |
| if (!GetUint8(raw, "length", length, context, error)) |
| return false; |
| |
| params = |
| WTF::WrapUnique(new WebCryptoAesCtrParams(length, std::move(counter))); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary AesGcmParams : Algorithm { |
| // required BufferSource iv; |
| // BufferSource additionalData; |
| // [EnforceRange] octet tagLength; |
| // } |
| bool ParseAesGcmParams(const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| WebVector<uint8_t> iv; |
| if (!GetBufferSource(raw, "iv", iv, context, error)) |
| return false; |
| |
| bool has_additional_data; |
| WebVector<uint8_t> additional_data; |
| if (!GetOptionalBufferSource(raw, "additionalData", has_additional_data, |
| additional_data, context, error)) |
| return false; |
| |
| uint8_t tag_length = 0; |
| bool has_tag_length; |
| if (!GetOptionalUint8(raw, "tagLength", has_tag_length, tag_length, context, |
| error)) |
| return false; |
| |
| params = WTF::WrapUnique(new WebCryptoAesGcmParams( |
| std::move(iv), has_additional_data, std::move(additional_data), |
| has_tag_length, tag_length)); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary RsaOaepParams : Algorithm { |
| // BufferSource label; |
| // }; |
| bool ParseRsaOaepParams(const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| bool has_label; |
| WebVector<uint8_t> label; |
| if (!GetOptionalBufferSource(raw, "label", has_label, label, context, error)) |
| return false; |
| |
| params = |
| WTF::WrapUnique(new WebCryptoRsaOaepParams(has_label, std::move(label))); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary RsaPssParams : Algorithm { |
| // [EnforceRange] required unsigned long saltLength; |
| // }; |
| bool ParseRsaPssParams(const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| uint32_t salt_length_bytes; |
| if (!GetUint32(raw, "saltLength", salt_length_bytes, context, error)) |
| return false; |
| |
| params = WTF::MakeUnique<WebCryptoRsaPssParams>(salt_length_bytes); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary EcdsaParams : Algorithm { |
| // required HashAlgorithmIdentifier hash; |
| // }; |
| bool ParseEcdsaParams(const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| WebCryptoAlgorithm hash; |
| if (!ParseHash(raw, hash, context, error)) |
| return false; |
| |
| params = WTF::MakeUnique<WebCryptoEcdsaParams>(hash); |
| return true; |
| } |
| |
| struct CurveNameMapping { |
| const char* const name; |
| WebCryptoNamedCurve value; |
| }; |
| |
| const CurveNameMapping kCurveNameMappings[] = { |
| {"P-256", kWebCryptoNamedCurveP256}, |
| {"P-384", kWebCryptoNamedCurveP384}, |
| {"P-521", kWebCryptoNamedCurveP521}}; |
| |
| // Reminder to update curveNameMappings when adding a new curve. |
| static_assert(kWebCryptoNamedCurveLast + 1 == |
| WTF_ARRAY_LENGTH(kCurveNameMappings), |
| "curveNameMappings needs to be updated"); |
| |
| bool ParseNamedCurve(const Dictionary& raw, |
| WebCryptoNamedCurve& named_curve, |
| ErrorContext context, |
| AlgorithmError* error) { |
| String named_curve_string; |
| if (!DictionaryHelper::Get(raw, "namedCurve", named_curve_string)) { |
| SetTypeError(context.ToString("namedCurve", "Missing or not a string"), |
| error); |
| return false; |
| } |
| |
| for (size_t i = 0; i < WTF_ARRAY_LENGTH(kCurveNameMappings); ++i) { |
| if (kCurveNameMappings[i].name == named_curve_string) { |
| named_curve = kCurveNameMappings[i].value; |
| return true; |
| } |
| } |
| |
| SetNotSupportedError(context.ToString("Unrecognized namedCurve"), error); |
| return false; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary EcKeyGenParams : Algorithm { |
| // required NamedCurve namedCurve; |
| // }; |
| bool ParseEcKeyGenParams(const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| WebCryptoNamedCurve named_curve; |
| if (!ParseNamedCurve(raw, named_curve, context, error)) |
| return false; |
| |
| params = WTF::MakeUnique<WebCryptoEcKeyGenParams>(named_curve); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary EcKeyImportParams : Algorithm { |
| // required NamedCurve namedCurve; |
| // }; |
| bool ParseEcKeyImportParams(const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| WebCryptoNamedCurve named_curve; |
| if (!ParseNamedCurve(raw, named_curve, context, error)) |
| return false; |
| |
| params = WTF::MakeUnique<WebCryptoEcKeyImportParams>(named_curve); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary EcdhKeyDeriveParams : Algorithm { |
| // required CryptoKey public; |
| // }; |
| bool ParseEcdhKeyDeriveParams(const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| v8::Local<v8::Value> v8_value; |
| if (!raw.Get("public", v8_value)) { |
| SetTypeError(context.ToString("public", "Missing required property"), |
| error); |
| return false; |
| } |
| |
| CryptoKey* crypto_key = |
| V8CryptoKey::toImplWithTypeCheck(raw.GetIsolate(), v8_value); |
| if (!crypto_key) { |
| SetTypeError(context.ToString("public", "Must be a CryptoKey"), error); |
| return false; |
| } |
| |
| params = WTF::WrapUnique(new WebCryptoEcdhKeyDeriveParams(crypto_key->Key())); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary Pbkdf2Params : Algorithm { |
| // required BufferSource salt; |
| // [EnforceRange] required unsigned long iterations; |
| // required HashAlgorithmIdentifier hash; |
| // }; |
| bool ParsePbkdf2Params(const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| WebVector<uint8_t> salt; |
| if (!GetBufferSource(raw, "salt", salt, context, error)) |
| return false; |
| |
| uint32_t iterations; |
| if (!GetUint32(raw, "iterations", iterations, context, error)) |
| return false; |
| |
| WebCryptoAlgorithm hash; |
| if (!ParseHash(raw, hash, context, error)) |
| return false; |
| params = WTF::WrapUnique( |
| new WebCryptoPbkdf2Params(hash, std::move(salt), iterations)); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary AesDerivedKeyParams : Algorithm { |
| // [EnforceRange] required unsigned short length; |
| // }; |
| bool ParseAesDerivedKeyParams(const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| uint16_t length; |
| if (!GetUint16(raw, "length", length, context, error)) |
| return false; |
| |
| params = WTF::MakeUnique<WebCryptoAesDerivedKeyParams>(length); |
| return true; |
| } |
| |
| // Defined by the WebCrypto spec as: |
| // |
| // dictionary HkdfParams : Algorithm { |
| // required HashAlgorithmIdentifier hash; |
| // required BufferSource salt; |
| // required BufferSource info; |
| // }; |
| bool ParseHkdfParams(const Dictionary& raw, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| const ErrorContext& context, |
| AlgorithmError* error) { |
| WebCryptoAlgorithm hash; |
| if (!ParseHash(raw, hash, context, error)) |
| return false; |
| WebVector<uint8_t> salt; |
| if (!GetBufferSource(raw, "salt", salt, context, error)) |
| return false; |
| WebVector<uint8_t> info; |
| if (!GetBufferSource(raw, "info", info, context, error)) |
| return false; |
| |
| params = WTF::WrapUnique( |
| new WebCryptoHkdfParams(hash, std::move(salt), std::move(info))); |
| return true; |
| } |
| |
| bool ParseAlgorithmParams(const Dictionary& raw, |
| WebCryptoAlgorithmParamsType type, |
| std::unique_ptr<WebCryptoAlgorithmParams>& params, |
| ErrorContext& context, |
| AlgorithmError* error) { |
| switch (type) { |
| case kWebCryptoAlgorithmParamsTypeNone: |
| return true; |
| case kWebCryptoAlgorithmParamsTypeAesCbcParams: |
| context.Add("AesCbcParams"); |
| return ParseAesCbcParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypeAesKeyGenParams: |
| context.Add("AesKeyGenParams"); |
| return ParseAesKeyGenParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypeHmacImportParams: |
| context.Add("HmacImportParams"); |
| return ParseHmacImportParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypeHmacKeyGenParams: |
| context.Add("HmacKeyGenParams"); |
| return ParseHmacKeyGenParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams: |
| context.Add("RsaHashedKeyGenParams"); |
| return ParseRsaHashedKeyGenParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypeRsaHashedImportParams: |
| context.Add("RsaHashedImportParams"); |
| return ParseRsaHashedImportParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypeAesCtrParams: |
| context.Add("AesCtrParams"); |
| return ParseAesCtrParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypeAesGcmParams: |
| context.Add("AesGcmParams"); |
| return ParseAesGcmParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypeRsaOaepParams: |
| context.Add("RsaOaepParams"); |
| return ParseRsaOaepParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypeRsaPssParams: |
| context.Add("RsaPssParams"); |
| return ParseRsaPssParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypeEcdsaParams: |
| context.Add("EcdsaParams"); |
| return ParseEcdsaParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypeEcKeyGenParams: |
| context.Add("EcKeyGenParams"); |
| return ParseEcKeyGenParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypeEcKeyImportParams: |
| context.Add("EcKeyImportParams"); |
| return ParseEcKeyImportParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypeEcdhKeyDeriveParams: |
| context.Add("EcdhKeyDeriveParams"); |
| return ParseEcdhKeyDeriveParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypeAesDerivedKeyParams: |
| context.Add("AesDerivedKeyParams"); |
| return ParseAesDerivedKeyParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypeHkdfParams: |
| context.Add("HkdfParams"); |
| return ParseHkdfParams(raw, params, context, error); |
| case kWebCryptoAlgorithmParamsTypePbkdf2Params: |
| context.Add("Pbkdf2Params"); |
| return ParsePbkdf2Params(raw, params, context, error); |
| } |
| ASSERT_NOT_REACHED(); |
| return false; |
| } |
| |
| const char* OperationToString(WebCryptoOperation op) { |
| switch (op) { |
| case kWebCryptoOperationEncrypt: |
| return "encrypt"; |
| case kWebCryptoOperationDecrypt: |
| return "decrypt"; |
| case kWebCryptoOperationSign: |
| return "sign"; |
| case kWebCryptoOperationVerify: |
| return "verify"; |
| case kWebCryptoOperationDigest: |
| return "digest"; |
| case kWebCryptoOperationGenerateKey: |
| return "generateKey"; |
| case kWebCryptoOperationImportKey: |
| return "importKey"; |
| case kWebCryptoOperationGetKeyLength: |
| return "get key length"; |
| case kWebCryptoOperationDeriveBits: |
| return "deriveBits"; |
| case kWebCryptoOperationWrapKey: |
| return "wrapKey"; |
| case kWebCryptoOperationUnwrapKey: |
| return "unwrapKey"; |
| } |
| return 0; |
| } |
| |
| bool ParseAlgorithmDictionary(const String& algorithm_name, |
| const Dictionary& raw, |
| WebCryptoOperation op, |
| WebCryptoAlgorithm& algorithm, |
| ErrorContext context, |
| AlgorithmError* error) { |
| WebCryptoAlgorithmId algorithm_id; |
| if (!LookupAlgorithmIdByName(algorithm_name, algorithm_id)) { |
| SetNotSupportedError(context.ToString("Unrecognized name"), error); |
| return false; |
| } |
| |
| // Remove the "Algorithm:" prefix for all subsequent errors. |
| context.RemoveLast(); |
| |
| const WebCryptoAlgorithmInfo* algorithm_info = |
| WebCryptoAlgorithm::LookupAlgorithmInfo(algorithm_id); |
| |
| if (algorithm_info->operation_to_params_type[op] == |
| WebCryptoAlgorithmInfo::kUndefined) { |
| context.Add(algorithm_info->name); |
| SetNotSupportedError( |
| context.ToString("Unsupported operation", OperationToString(op)), |
| error); |
| return false; |
| } |
| |
| WebCryptoAlgorithmParamsType params_type = |
| static_cast<WebCryptoAlgorithmParamsType>( |
| algorithm_info->operation_to_params_type[op]); |
| |
| std::unique_ptr<WebCryptoAlgorithmParams> params; |
| if (!ParseAlgorithmParams(raw, params_type, params, context, error)) |
| return false; |
| |
| algorithm = WebCryptoAlgorithm(algorithm_id, std::move(params)); |
| return true; |
| } |
| |
| bool ParseAlgorithmIdentifier(const AlgorithmIdentifier& raw, |
| WebCryptoOperation op, |
| WebCryptoAlgorithm& algorithm, |
| ErrorContext context, |
| AlgorithmError* error) { |
| context.Add("Algorithm"); |
| |
| // If the AlgorithmIdentifier is a String, treat it the same as a Dictionary |
| // with a "name" attribute and nothing else. |
| if (raw.isString()) { |
| return ParseAlgorithmDictionary(raw.getAsString(), Dictionary(), op, |
| algorithm, context, error); |
| } |
| |
| Dictionary params = raw.getAsDictionary(); |
| |
| // Get the name of the algorithm from the AlgorithmIdentifier. |
| if (!params.IsObject()) { |
| SetTypeError(context.ToString("Not an object"), error); |
| return false; |
| } |
| |
| String algorithm_name; |
| if (!DictionaryHelper::Get(params, "name", algorithm_name)) { |
| SetTypeError(context.ToString("name", "Missing or not a string"), error); |
| return false; |
| } |
| |
| return ParseAlgorithmDictionary(algorithm_name, params, op, algorithm, |
| context, error); |
| } |
| |
| } // namespace |
| |
| bool NormalizeAlgorithm(const AlgorithmIdentifier& raw, |
| WebCryptoOperation op, |
| WebCryptoAlgorithm& algorithm, |
| AlgorithmError* error) { |
| return ParseAlgorithmIdentifier(raw, op, algorithm, ErrorContext(), error); |
| } |
| |
| } // namespace blink |