|
1 | 1 | private import csharp |
2 | | -private import Cryptography |
| 2 | +private import semmle.code.csharp.dataflow.DataFlow |
| 3 | +private import OperationInstances |
3 | 4 | private import AlgorithmValueConsumers |
4 | | - |
5 | | -/** |
6 | | - * Flow from a known ECDsa property access to a `ECDsa.Create(sink)` call. |
7 | | - */ |
8 | | -module SigningNamedCurveToSignatureCreateFlowConfig implements DataFlow::ConfigSig { |
9 | | - predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SigningNamedCurvePropertyAccess } |
10 | | - |
11 | | - predicate isSink(DataFlow::Node sink) { |
12 | | - exists(ECDsaAlgorithmValueConsumer consumer | sink = consumer.getInputNode()) |
13 | | - } |
14 | | -} |
15 | | - |
16 | | -module SigningNamedCurveToSignatureCreateFlow = |
17 | | - DataFlow::Global<SigningNamedCurveToSignatureCreateFlowConfig>; |
18 | | - |
19 | | -module HashAlgorithmNameToUseConfig implements DataFlow::ConfigSig { |
20 | | - predicate isSource(DataFlow::Node src) { src.asExpr() instanceof HashAlgorithmName } |
21 | | - |
22 | | - predicate isSink(DataFlow::Node sink) { |
23 | | - exists(HashAlgorithmNameConsumer consumer | sink = consumer.getInputNode()) |
24 | | - } |
25 | | -} |
26 | | - |
27 | | -module HashAlgorithmNameToUse = DataFlow::Global<HashAlgorithmNameToUseConfig>; |
| 5 | +private import Cryptography |
28 | 6 |
|
29 | 7 | signature class CreationCallSig instanceof Call; |
30 | 8 |
|
31 | 9 | signature class UseCallSig instanceof QualifiableExpr { |
32 | 10 | predicate isIntermediate(); |
33 | 11 | } |
34 | 12 |
|
35 | | -module CryptographyCreateToUseFlow = CreationToUseFlow<CryptographyCreateCall, DotNetSigner>; |
36 | | - |
37 | 13 | module CreationToUseFlow<CreationCallSig Creation, UseCallSig Use> { |
38 | 14 | private module CreationToUseConfig implements DataFlow::ConfigSig { |
39 | 15 | predicate isSource(DataFlow::Node source) { |
@@ -85,3 +61,159 @@ module CreationToUseFlow<CreationCallSig Creation, UseCallSig Use> { |
85 | 61 | ) |
86 | 62 | } |
87 | 63 | } |
| 64 | + |
| 65 | +/** |
| 66 | + * Flow from a known ECDsa property access to a `ECDsa.Create(sink)` call. |
| 67 | + */ |
| 68 | +module SigningNamedCurveToSignatureCreateFlowConfig implements DataFlow::ConfigSig { |
| 69 | + predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SigningNamedCurvePropertyAccess } |
| 70 | + |
| 71 | + predicate isSink(DataFlow::Node sink) { |
| 72 | + exists(ECDsaAlgorithmValueConsumer consumer | sink = consumer.getInputNode()) |
| 73 | + } |
| 74 | +} |
| 75 | + |
| 76 | +module SigningNamedCurveToSignatureCreateFlow = |
| 77 | + DataFlow::Global<SigningNamedCurveToSignatureCreateFlowConfig>; |
| 78 | + |
| 79 | +module HashAlgorithmNameToUseConfig implements DataFlow::ConfigSig { |
| 80 | + predicate isSource(DataFlow::Node src) { src.asExpr() instanceof HashAlgorithmName } |
| 81 | + |
| 82 | + predicate isSink(DataFlow::Node sink) { |
| 83 | + exists(HashAlgorithmNameConsumer consumer | sink = consumer.getInputNode()) |
| 84 | + } |
| 85 | +} |
| 86 | + |
| 87 | +module HashAlgorithmNameToUse = DataFlow::Global<HashAlgorithmNameToUseConfig>; |
| 88 | + |
| 89 | +module CryptographyCreateToUseFlow = CreationToUseFlow<CryptographyCreateCall, DotNetSigner>; |
| 90 | + |
| 91 | +/** |
| 92 | + * A flow analysis module that tracks the flow from a `CryptoStreamMode.READ` or |
| 93 | + * `CryptoStreamMode.WRITE` access to the corresponding `CryptoStream` object |
| 94 | + * creation. |
| 95 | + */ |
| 96 | +module CryptoStreamModeFlow { |
| 97 | + private module CryptoStreamModeConfig implements DataFlow::ConfigSig { |
| 98 | + predicate isSource(DataFlow::Node source) { |
| 99 | + source.asExpr() = any(CryptoStreamMode mode).getAnAccess() |
| 100 | + } |
| 101 | + |
| 102 | + predicate isSink(DataFlow::Node sink) { |
| 103 | + sink.asExpr() = any(CryptoStreamCreation creation).getModeArg() |
| 104 | + } |
| 105 | + } |
| 106 | + |
| 107 | + private module CryptoStreamModeFlow = DataFlow::Global<CryptoStreamModeConfig>; |
| 108 | + |
| 109 | + CryptoStreamMode getModeFromCreation(CryptoStreamCreation creation) { |
| 110 | + exists(CryptoStreamModeFlow::PathNode source, CryptoStreamModeFlow::PathNode sink | |
| 111 | + source.getNode().asExpr() = result.getAnAccess() and |
| 112 | + sink.getNode().asExpr() = creation.getAnArgument() and |
| 113 | + CryptoStreamModeFlow::flowPath(source, sink) |
| 114 | + ) |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +/** |
| 119 | + * A flow analysis module that tracks data flow from a `ICryptoTransform` |
| 120 | + * creation (e.g. `Aes.CreateEncryptor()`) to the transform argument of a |
| 121 | + * `CryptoStream` object creation. |
| 122 | + */ |
| 123 | +module CryptoTransformFlow { |
| 124 | + private module CryptoTransformConfig implements DataFlow::ConfigSig { |
| 125 | + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CryptoTransformCreation } |
| 126 | + |
| 127 | + predicate isSink(DataFlow::Node sink) { |
| 128 | + sink.asExpr() = any(ObjectCreation creation).getAnArgument() |
| 129 | + } |
| 130 | + } |
| 131 | + |
| 132 | + private module CryptoTransformFlow = DataFlow::Global<CryptoTransformConfig>; |
| 133 | + |
| 134 | + CryptoTransformCreation getCreationFromUse(ObjectCreation creation) { |
| 135 | + exists(CryptoTransformFlow::PathNode source, CryptoTransformFlow::PathNode sink | |
| 136 | + source.getNode().asExpr() = result and |
| 137 | + sink.getNode().asExpr() = creation.getAnArgument() and |
| 138 | + CryptoTransformFlow::flowPath(source, sink) |
| 139 | + ) |
| 140 | + } |
| 141 | +} |
| 142 | + |
| 143 | +/** |
| 144 | + * A flow analysis module that tracks the flow from a `PaddingMode` member |
| 145 | + * access (e.g. `PaddingMode.PKCS7`) to a `Padding` property write on a |
| 146 | + * `SymmetricAlgorithm` instance. |
| 147 | + * |
| 148 | + * Example: |
| 149 | + * ``` |
| 150 | + * Aes aes = Aes.Create(); |
| 151 | + * aes.Padding = PaddingMode.PKCS7; |
| 152 | + * ... |
| 153 | + * ``` |
| 154 | + */ |
| 155 | +module PaddingModeLiteralFlow { |
| 156 | + private module PaddingModeLiteralConfig implements DataFlow::ConfigSig { |
| 157 | + predicate isSource(DataFlow::Node source) { |
| 158 | + source.asExpr() = any(PaddingMode mode).getAnAccess() |
| 159 | + } |
| 160 | + |
| 161 | + predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof PaddingPropertyWrite } |
| 162 | + |
| 163 | + // TODO: Figure out why this is needed. |
| 164 | + predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { |
| 165 | + exists(Assignment assign | |
| 166 | + node1.asExpr() = assign.getRValue() and |
| 167 | + node2.asExpr() = assign.getLValue() |
| 168 | + ) |
| 169 | + } |
| 170 | + } |
| 171 | + |
| 172 | + private module PaddingModeLiteralFlow = DataFlow::Global<PaddingModeLiteralConfig>; |
| 173 | + |
| 174 | + SymmetricAlgorithmUse getConsumer( |
| 175 | + Expr mode, PaddingModeLiteralFlow::PathNode source, PaddingModeLiteralFlow::PathNode sink |
| 176 | + ) { |
| 177 | + source.getNode().asExpr() = mode and |
| 178 | + sink.getNode().asExpr() = result and |
| 179 | + PaddingModeLiteralFlow::flowPath(source, sink) |
| 180 | + } |
| 181 | +} |
| 182 | + |
| 183 | +/** |
| 184 | + * A flow analysis module that tracks the flow from a `MemoryStream` object |
| 185 | + * creation to the `stream` argument passed to a `CryptoStream` constructor |
| 186 | + * call. |
| 187 | + * |
| 188 | + * TODO: This should probably be made generic over multiple stream types. |
| 189 | + */ |
| 190 | +module MemoryStreamFlow { |
| 191 | + private class MemoryStreamCreation extends ObjectCreation { |
| 192 | + MemoryStreamCreation() { |
| 193 | + this.getObjectType().hasFullyQualifiedName("System.IO", "MemoryStream") |
| 194 | + } |
| 195 | + |
| 196 | + Expr getBufferArg() { result = this.getArgument(0) } |
| 197 | + } |
| 198 | + |
| 199 | + // (Note that we cannot use `CreationToUseFlow` here, because the use is not a |
| 200 | + // `QualifiableExpr`.) |
| 201 | + private module MemoryStreamConfig implements DataFlow::ConfigSig { |
| 202 | + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof MemoryStreamCreation } |
| 203 | + |
| 204 | + predicate isSink(DataFlow::Node sink) { |
| 205 | + exists(CryptoStreamCreation creation | sink.asExpr() = creation.getStreamArg()) |
| 206 | + } |
| 207 | + } |
| 208 | + |
| 209 | + private module MemoryStreamFlow = DataFlow::Global<MemoryStreamConfig>; |
| 210 | + |
| 211 | + MemoryStreamCreation getCreationFromUse( |
| 212 | + CryptoStreamCreation creation, MemoryStreamFlow::PathNode source, |
| 213 | + MemoryStreamFlow::PathNode sink |
| 214 | + ) { |
| 215 | + source.getNode().asExpr() = result and |
| 216 | + sink.getNode().asExpr() = creation.getStreamArg() and |
| 217 | + MemoryStreamFlow::flowPath(source, sink) |
| 218 | + } |
| 219 | +} |
0 commit comments