Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(416)

Side by Side Diff: Source/core/frame/SubresourceIntegrity.cpp

Issue 1126343003: Ignore unknown options to subresource integrity (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "config.h" 5 #include "config.h"
6 #include "core/frame/SubresourceIntegrity.h" 6 #include "core/frame/SubresourceIntegrity.h"
7 7
8 #include "core/HTMLNames.h" 8 #include "core/HTMLNames.h"
9 #include "core/dom/Document.h" 9 #include "core/dom/Document.h"
10 #include "core/dom/Element.h" 10 #include "core/dom/Element.h"
(...skipping 22 matching lines...) Expand all
33 // Check if it's a base64 encoded value. We're pretty loose here, as there's 33 // Check if it's a base64 encoded value. We're pretty loose here, as there's
34 // not much risk in it, and it'll make it simpler for developers. 34 // not much risk in it, and it'll make it simpler for developers.
35 return isASCIIAlphanumeric(c) || c == '_' || c == '-' || c == '+' || c == '/ ' || c == '='; 35 return isASCIIAlphanumeric(c) || c == '_' || c == '-' || c == '+' || c == '/ ' || c == '=';
36 } 36 }
37 37
38 static bool isTypeCharacter(UChar c) 38 static bool isTypeCharacter(UChar c)
39 { 39 {
40 return isASCIIAlphanumeric(c) || c == '+' || c == '.' || c == '-'; 40 return isASCIIAlphanumeric(c) || c == '+' || c == '.' || c == '-';
41 } 41 }
42 42
43 static bool isOptionNameCharacter(UChar c)
44 {
45 return isASCIIAlphanumeric(c) || c == '-';
46 }
47
48 static bool isOptionValueCharacter(UChar c)
49 {
50 return isASCIIAlphanumeric(c) || c == '!' || c == '#' || c == '$' || c == '% ' || c == '&' || c == '\'' || c == '*' || c == '+' || c == '-' || c == '.' || c == '^' || c == '_' || c == '`' || c == '|' || c == '~' || c == '/';
51 }
52
43 static void logErrorToConsole(const String& message, Document& document) 53 static void logErrorToConsole(const String& message, Document& document)
44 { 54 {
45 document.addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, Err orMessageLevel, message)); 55 document.addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, Err orMessageLevel, message));
46 } 56 }
47 57
48 static bool DigestsEqual(const DigestValue& digest1, const DigestValue& digest2) 58 static bool DigestsEqual(const DigestValue& digest1, const DigestValue& digest2)
49 { 59 {
50 if (digest1.size() != digest2.size()) 60 if (digest1.size() != digest2.size())
51 return false; 61 return false;
52 62
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 if (position == begin || (position != end && *position != '?')) { 206 if (position == begin || (position != end && *position != '?')) {
197 digest = emptyString(); 207 digest = emptyString();
198 return false; 208 return false;
199 } 209 }
200 210
201 // We accept base64url encoding, but normalize to "normal" base64 internally : 211 // We accept base64url encoding, but normalize to "normal" base64 internally :
202 digest = normalizeToBase64(String(begin, position - begin)); 212 digest = normalizeToBase64(String(begin, position - begin));
203 return true; 213 return true;
204 } 214 }
205 215
216 bool SubresourceIntegrity::isValidMimeTypeValue(const String& value)
217 {
218 Vector<UChar> characters;
219 value.appendTo(characters);
220 const UChar* position = characters.data();
221 const UChar* end = characters.end();
206 222
207 // Before:
208 //
209 // [algorithm]-[hash] OR [algorithm]-[hash]?[options]
210 // ^ ^ ^
211 // position/end position end
212 //
213 // After (if successful: if the method returns false, we make no promises and th e caller should exit early):
214 //
215 // [algorithm]-[hash] OR [algorithm]-[hash]?[options]
216 // ^ ^
217 // position/end position/end
218 bool SubresourceIntegrity::parseMimeType(const UChar*& position, const UChar* en d, String& type)
219 {
220 type = emptyString();
221
222 if (position == end)
223 return true;
224
225 if (!skipToken<UChar>(position, end, "?ct="))
226 return false;
227
228 const UChar* begin = position;
229 skipWhile<UChar, isASCIIAlpha>(position, end); 223 skipWhile<UChar, isASCIIAlpha>(position, end);
230 if (position == end) 224 if (position == end)
231 return false; 225 return false;
232 226
233 if (!skipExactly<UChar>(position, end, '/')) 227 if (!skipExactly<UChar>(position, end, '/'))
234 return false; 228 return false;
235 229
236 if (position == end)
237 return false;
238
239 skipWhile<UChar, isTypeCharacter>(position, end); 230 skipWhile<UChar, isTypeCharacter>(position, end);
240 if (position != end) 231 if (position != end)
241 return false; 232 return false;
242 233
243 type = String(begin, position - begin);
244 return true; 234 return true;
245 } 235 }
246 236
237
238 // Before:
239 //
240 // [algorithm]-[hash] OR [algorithm]-[hash]?[name]=[value] OR [algorithm]-[hash]?[name]=[value]?[rest of options]
241 // ^ ^ ^ ^ ^
242 // position/end position end position end
243 //
244 // After (if successful: if the method returns false, we make no promises and th e caller should exit early):
245 //
246 // [algorithm]-[hash] OR [algorithm]-[hash]?[name]=[value] OR [algorithm]-[hash]?[name]=[value]?[rest of options]
Mike West 2015/05/11 03:25:28 This is such a weird syntax.
247 // ^ ^ ^ ^
248 // position/end position/end position end
249 bool SubresourceIntegrity::parseOption(const UChar*& position, const UChar* end, String& name, String& value)
250 {
251 name = emptyString();
252 value = emptyString();
253
254 if (position == end)
255 return true;
256
257 if (!skipExactly<UChar>(position, end, '?'))
258 return false;
259
260 const UChar* begin = position;
261 skipWhile<UChar, isOptionNameCharacter>(position, end);
262 if (position == end)
263 return false;
264
265 name = String(begin, position - begin);
266
267 if (!skipExactly<UChar>(position, end, '=') || position == end)
268 return false;
269
270 begin = position;
271 skipWhile<UChar, isOptionValueCharacter>(position, end);
272
273 value = String(begin, position - begin);
274
275 if (position == end || *position == '?')
Mike West 2015/05/11 03:25:28 Would you mind asserting that `position < end` bef
276 return true;
277
278 return false;
279 }
280
247 SubresourceIntegrity::IntegrityParseResult SubresourceIntegrity::parseIntegrityA ttribute(const WTF::String& attribute, WTF::Vector<IntegrityMetadata>& metadataL ist, Document& document) 281 SubresourceIntegrity::IntegrityParseResult SubresourceIntegrity::parseIntegrityA ttribute(const WTF::String& attribute, WTF::Vector<IntegrityMetadata>& metadataL ist, Document& document)
248 { 282 {
249 Vector<UChar> characters; 283 Vector<UChar> characters;
250 attribute.stripWhiteSpace().appendTo(characters); 284 attribute.stripWhiteSpace().appendTo(characters);
251 const UChar* position = characters.data(); 285 const UChar* position = characters.data();
252 const UChar* end = characters.end(); 286 const UChar* end = characters.end();
253 const UChar* currentIntegrityEnd; 287 const UChar* currentIntegrityEnd;
254 288
255 metadataList.clear(); 289 metadataList.clear();
256 bool error = false; 290 bool error = false;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
293 ASSERT(parseResult == AlgorithmValid); 327 ASSERT(parseResult == AlgorithmValid);
294 328
295 if (!parseDigest(position, currentIntegrityEnd, digest)) { 329 if (!parseDigest(position, currentIntegrityEnd, digest)) {
296 logErrorToConsole("Error parsing 'integrity' attribute ('" + attribu te + "'). The digest must be a valid, base64-encoded value.", document); 330 logErrorToConsole("Error parsing 'integrity' attribute ('" + attribu te + "'). The digest must be a valid, base64-encoded value.", document);
297 error = true; 331 error = true;
298 skipUntil<UChar, isASCIISpace>(position, end); 332 skipUntil<UChar, isASCIISpace>(position, end);
299 UseCounter::count(document, UseCounter::SRIElementWithUnparsableInte grityAttribute); 333 UseCounter::count(document, UseCounter::SRIElementWithUnparsableInte grityAttribute);
300 continue; 334 continue;
301 } 335 }
302 336
303 if (!parseMimeType(position, currentIntegrityEnd, type)) { 337 bool skipToNextIntegrity = false;
304 logErrorToConsole("Error parsing 'integrity' attribute ('" + attribu te + "'). The content type could not be parsed.", document); 338 while (*position == '?') {
305 error = true; 339 String name, value;
306 skipUntil<UChar, isASCIISpace>(position, end); 340 if (!parseOption(position, currentIntegrityEnd, name, value)) {
307 UseCounter::count(document, UseCounter::SRIElementWithUnparsableInte grityAttribute); 341 logErrorToConsole("Error parsing 'integrity' attribute ('" + att ribute + "'). The options could not be parsed.", document);
342 skipToNextIntegrity = true;
343 error = true;
344 skipUntil<UChar, isASCIISpace>(position, end);
345 UseCounter::count(document, UseCounter::SRIElementWithUnparsable IntegrityAttribute);
346 break;
347 }
348
349 if (name == "ct") {
350 if (!isValidMimeTypeValue(value)) {
351 logErrorToConsole("Error parsing 'integrity' attribute ('" + attribute + "'). The content type could not be parsed.", document);
352 skipToNextIntegrity = true;
353 error = true;
354 skipUntil<UChar, isASCIISpace>(position, end);
355 UseCounter::count(document, UseCounter::SRIElementWithUnpars ableIntegrityAttribute);
356 break;
357 }
358
359 type = value;
360 } else {
361 logErrorToConsole("Ignoring unrecogized 'integrity' attribute op tion '" + name + "' with value '" + value + "'.", document);
362 }
363 }
364
365 if (skipToNextIntegrity)
308 continue; 366 continue;
309 }
310 367
311 IntegrityMetadata integrityMetadata = { 368 IntegrityMetadata integrityMetadata = {
312 digest, 369 digest,
313 algorithm, 370 algorithm,
314 type 371 type
315 }; 372 };
316 metadataList.append(integrityMetadata); 373 metadataList.append(integrityMetadata);
317 } 374 }
318 375
319 if (metadataList.size() == 0 && error) 376 if (metadataList.size() == 0 && error)
320 return IntegrityParseNoValidResult; 377 return IntegrityParseNoValidResult;
321 378
322 return IntegrityParseValidResult; 379 return IntegrityParseValidResult;
323 } 380 }
324 381
325 } // namespace blink 382 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698