|
1 | | -import java |
2 | | -import semmle.code.java.dataflow.DefUse |
3 | | -import semmle.code.java.dataflow.DataFlow6 |
4 | | - |
5 | 1 | /** |
6 | | - * The `java.security.SecureRandom` class. |
| 2 | + * Defines classes representing random data sources. |
7 | 3 | */ |
8 | | -class SecureRandomNumberGenerator extends RefType { |
9 | | - SecureRandomNumberGenerator() { this.hasQualifiedName("java.security", "SecureRandom") } |
10 | | -} |
| 4 | + |
| 5 | +import java |
11 | 6 |
|
12 | 7 | /** |
13 | 8 | * A method access that returns random data or writes random data to an argument. |
@@ -148,149 +143,3 @@ class ApacheCommonsRandomSource extends RandomDataSource { |
148 | 143 |
|
149 | 144 | override Expr getOutput() { result = this } |
150 | 145 | } |
151 | | - |
152 | | -/** |
153 | | - * A method access calling a method declared on `java.security.SecureRandom` |
154 | | - * that returns random data or writes random data to an argument. |
155 | | - */ |
156 | | -class GetRandomData extends StdlibRandomSource { |
157 | | - GetRandomData() { this.getQualifier().getType() instanceof SecureRandomNumberGenerator } |
158 | | -} |
159 | | - |
160 | | -private predicate isSeeded(RValue use) { |
161 | | - isSeeding(_, use) |
162 | | - or |
163 | | - exists(GetRandomData da, RValue seeduse | |
164 | | - da.getQualifier() = seeduse and |
165 | | - useUsePair(seeduse, use) |
166 | | - ) |
167 | | -} |
168 | | - |
169 | | -private class PredictableSeedFlowConfiguration extends DataFlow6::Configuration { |
170 | | - PredictableSeedFlowConfiguration() { this = "Random::PredictableSeedFlowConfiguration" } |
171 | | - |
172 | | - override predicate isSource(DataFlow6::Node source) { |
173 | | - source.asExpr() instanceof PredictableSeedExpr |
174 | | - } |
175 | | - |
176 | | - override predicate isSink(DataFlow6::Node sink) { isSeeding(sink.asExpr(), _) } |
177 | | - |
178 | | - override predicate isAdditionalFlowStep(DataFlow6::Node node1, DataFlow6::Node node2) { |
179 | | - predictableCalcStep(node1.asExpr(), node2.asExpr()) |
180 | | - } |
181 | | -} |
182 | | - |
183 | | -private predicate predictableCalcStep(Expr e1, Expr e2) { |
184 | | - e2.(BinaryExpr).hasOperands(e1, any(PredictableSeedExpr p)) |
185 | | - or |
186 | | - exists(AssignOp a | a = e2 | e1 = a.getDest() and a.getRhs() instanceof PredictableSeedExpr) |
187 | | - or |
188 | | - exists(ConstructorCall cc, TypeNumber t | cc = e2 | |
189 | | - cc.getArgument(0) = e1 and |
190 | | - t.hasSubtype*(cc.getConstructedType()) |
191 | | - ) |
192 | | - or |
193 | | - exists(Method m, MethodAccess ma | |
194 | | - ma = e2 and |
195 | | - e1 = ma.getQualifier() and |
196 | | - m = ma.getMethod() and |
197 | | - exists(TypeNumber t | hasSubtype*(t, m.getDeclaringType())) and |
198 | | - ( |
199 | | - m.getName().matches("to%String") or |
200 | | - m.getName() = "toByteArray" or |
201 | | - m.getName().matches("%Value") |
202 | | - ) |
203 | | - ) |
204 | | - or |
205 | | - exists(Method m, MethodAccess ma | |
206 | | - ma = e2 and |
207 | | - e1 = ma.getArgument(0) and |
208 | | - m = ma.getMethod() and |
209 | | - exists(TypeNumber t | hasSubtype*(t, m.getDeclaringType())) and |
210 | | - ( |
211 | | - m.getName().matches("parse%") or |
212 | | - m.getName().matches("valueOf%") or |
213 | | - m.getName().matches("to%String") |
214 | | - ) |
215 | | - ) |
216 | | -} |
217 | | - |
218 | | -private predicate safelySeeded(RValue use) { |
219 | | - exists(Expr arg | |
220 | | - isSeeding(arg, use) and |
221 | | - not exists(PredictableSeedFlowConfiguration conf | conf.hasFlowToExpr(arg)) |
222 | | - ) |
223 | | - or |
224 | | - exists(GetRandomData da, RValue seeduse | |
225 | | - da.getQualifier() = seeduse and useUsePair(seeduse, use) |
226 | | - | |
227 | | - not exists(RValue prior | useUsePair(prior, seeduse) | isSeeded(prior)) |
228 | | - ) |
229 | | -} |
230 | | - |
231 | | -predicate unsafelySeeded(RValue use, PredictableSeedExpr source) { |
232 | | - isSeedingSource(_, use, source) and |
233 | | - not safelySeeded(use) |
234 | | -} |
235 | | - |
236 | | -private predicate isSeeding(Expr arg, RValue use) { |
237 | | - exists(Expr e, VariableAssign def | |
238 | | - def.getSource() = e and |
239 | | - isSeedingConstruction(e, arg) |
240 | | - | |
241 | | - defUsePair(def, use) or |
242 | | - def.getDestVar().(Field).getAnAccess() = use |
243 | | - ) |
244 | | - or |
245 | | - exists(Expr e, RValue seeduse | |
246 | | - e.(MethodAccess).getQualifier() = seeduse and |
247 | | - isRandomSeeding(e, arg) and |
248 | | - useUsePair(seeduse, use) |
249 | | - ) |
250 | | -} |
251 | | - |
252 | | -private predicate isSeedingSource(Expr arg, RValue use, Expr source) { |
253 | | - isSeeding(arg, use) and |
254 | | - exists(PredictableSeedFlowConfiguration conf | |
255 | | - conf.hasFlow(DataFlow6::exprNode(source), DataFlow6::exprNode(arg)) |
256 | | - ) |
257 | | -} |
258 | | - |
259 | | -private predicate isRandomSeeding(MethodAccess m, Expr arg) { |
260 | | - exists(Method def | m.getMethod() = def | |
261 | | - def.getDeclaringType() instanceof SecureRandomNumberGenerator and |
262 | | - def.getName() = "setSeed" and |
263 | | - arg = m.getArgument(0) |
264 | | - ) |
265 | | -} |
266 | | - |
267 | | -private predicate isSeedingConstruction(ClassInstanceExpr c, Expr arg) { |
268 | | - c.getConstructedType() instanceof SecureRandomNumberGenerator and |
269 | | - c.getNumArgument() = 1 and |
270 | | - c.getArgument(0) = arg |
271 | | -} |
272 | | - |
273 | | -class PredictableSeedExpr extends Expr { |
274 | | - PredictableSeedExpr() { |
275 | | - this.(MethodAccess).getCallee() instanceof ReturnsPredictableExpr |
276 | | - or |
277 | | - this instanceof CompileTimeConstantExpr |
278 | | - or |
279 | | - this.(ArrayCreationExpr).getInit() instanceof PredictableSeedExpr |
280 | | - or |
281 | | - exists(ArrayInit init | init = this | |
282 | | - forall(Expr e | e = init.getAnInit() | e instanceof PredictableSeedExpr) |
283 | | - ) |
284 | | - } |
285 | | -} |
286 | | - |
287 | | -abstract class ReturnsPredictableExpr extends Method { } |
288 | | - |
289 | | -class ReturnsSystemTime extends ReturnsPredictableExpr { |
290 | | - ReturnsSystemTime() { |
291 | | - this.getDeclaringType().hasQualifiedName("java.lang", "System") and |
292 | | - this.hasName("currentTimeMillis") |
293 | | - or |
294 | | - this.getDeclaringType().hasQualifiedName("java.lang", "System") and this.hasName("nanoTime") |
295 | | - } |
296 | | -} |
0 commit comments