/**
* Find Security Bugs
* Copyright (c) Philippe Arteau, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.h3xstream.findsecbugs.taintanalysis;
import java.io.IOException;
import java.util.regex.Pattern;
/**
* Summary of information about a class related to taint analysis,
* allows to configure default behavior for return types and type casts.
*
* Default configuration is mutable class with null taint state.
*
* @author Tomas Polesovsky (Liferay, Inc.)
*/
public class TaintClassConfig implements TaintTypeConfig {
public static final Taint.State DEFAULT_TAINT_STATE = Taint.State.NULL;
private static final String IMMUTABLE = "#IMMUTABLE";
private Taint.State taintState = DEFAULT_TAINT_STATE;
private boolean immutable;
private static final Pattern typePattern;
private static final Pattern taintConfigPattern;
static {
String javaIdentifierRegex = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*";
String classWithPackageRegex = javaIdentifierRegex+"(\\/"+javaIdentifierRegex+")*";
String typeRegex = "(\\[)*((L" + classWithPackageRegex + ";)|B|C|D|F|I|J|S|Z)";
typePattern = Pattern.compile(typeRegex);
String taintConfigRegex = "([A-Z_]+|#IMMUTABLE|[A-Z_]+#IMMUTABLE)";
taintConfigPattern = Pattern.compile(taintConfigRegex);
}
public static boolean accepts(String typeSignature, String taintConfig) {
return typePattern.matcher(typeSignature).matches() && taintConfigPattern.matcher(taintConfig).matches();
}
/**
* Loads class summary from String<br/>
* <br/>
* The summary should have the following syntax:<br />
* <code>defaultTaintState #IMMUTABLE</code>, where <ol>
* <li><code>defaultTaintState</code> means the Taint state for type casting and return types. Usually <code>SAFE</code> is used to specify classes that cannot contain injection escape characters</li>
* <li><code>#IMMUTABLE</code> flags is used for classes that cannot be subject to taint state mutation during taint analysis</li>
* <li>at least one of two above are required</li>
* </ol>
*
* Example: <br/>
* <code>Ljava/lang/Boolean;:SAFE#IMMUTABLE</code><br />
* <ul>
* <li>Here the summary is: <code>SAFE#IMMUTABLE</code></li>
* <li>When a object is casted to Boolean or Boolean is a method result type, the taint state will be always SAFE</li>
* <li>When applying taint mutation to method arguments, Boolean arguments cannot change taint state</li>
* <li>Practically, Booleans cannot transfer characters that could cause injections and thus are SAFE as return types and casts</li>
* </ul>
*
* Example: <br/>
* <code>Ljava/lang/String;:#IMMUTABLE</code><br />
* <ul>
* <li>String is immutable class and therefore String method arguments cannot change taint state</li>
* <li>Practically, String can carry injection sensitive characters but is always immutable</li>
* </ul>
*
* Example: <br/>
* <code>Ljava/util/concurrent/atomic/AtomicBoolean;:SAFE</code><br />
* <ul>
* <li>AtomicBoolean value can be changed but cannot carry injection sensitive value</li>
* </ul>
*
* @param taintConfig <code>state#IMMUTABLE</code>, where state is one of Taint.STATE or empty
* @return initialized object with taint class summary
* @throws java.io.IOException for bad format of parameter
* @throws NullPointerException if argument is null
*/
@Override
public TaintClassConfig load(String taintConfig) throws IOException {
if (taintConfig == null) {
throw new NullPointerException("Taint config is null");
}
taintConfig = taintConfig.trim();
if (taintConfig.isEmpty()) {
throw new IOException("No taint class config specified");
}
TaintClassConfig taintClassConfig = new TaintClassConfig();
if (taintConfig.endsWith(IMMUTABLE)) {
taintClassConfig.immutable = true;
taintConfig = taintConfig.substring(0, taintConfig.length() - IMMUTABLE.length());
}
if (!taintConfig.isEmpty()) {
taintClassConfig.taintState = Taint.State.valueOf(taintConfig);
}
return taintClassConfig;
}
public Taint.State getTaintState() {
return taintState;
}
public boolean isImmutable() {
return immutable;
}
public Taint.State getTaintState(Taint.State defaultState) {
if (taintState.equals(DEFAULT_TAINT_STATE)) {
return defaultState;
}
return taintState;
}
}
/* @generated */