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