-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathCryptoArtifact.qll
316 lines (272 loc) · 12.1 KB
/
CryptoArtifact.qll
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
import cpp
private import experimental.cryptography.CryptoAlgorithmNames
import semmle.code.cpp.ir.dataflow.TaintTracking
/*
* A cryptographic artifact is a DataFlow::Node associated with some
* operation, algorithm, or any other aspect of cryptography.
*/
abstract class CryptographicArtifact extends Expr { }
// /**
// * Associates a symmetric encryption algorithm with a block mode.
// * The DataFlow::Node representing this association should be the
// * point where the algorithm and block mode are combined.
// * This may be at the call to encryption or in the construction
// * of an object prior to encryption.
// */
// abstract class SymmetricCipher extends CryptographicArtifact{
// abstract SymmetricEncryptionAlgorithm getEncryptionAlgorithm();
// abstract BlockMode getBlockMode();
// final predicate hasBlockMode(){
// exists(this.getBlockMode())
// }
// }
// /**
// * A cryptographic operation is a method call that invokes a cryptographic
// * algorithm (encrypt/decrypt) or a function in support of a cryptographic algorithm
// * (key generation).
// *
// * Since operations are related to or in support of algorithms, operations must
// * provide a reference to their associated algorithm. Often operataions themselves
// * encapsulate algorithms, so operations can also extend CryptographicAlgorithm
// * and refer to themselves as the target algorithm.
// */
// abstract class CryptographicOperation extends CryptographicArtifact, Call{
// // bindingset[paramName, ind]
// // final DataFlow::Node getParameterSource(int ind, string paramName){
// // result = Utils::getUltimateSrcFromApiNode(this.(API::CallNode).getParameter(ind, paramName))
// // }
// final string getAlgorithmName(){
// if exists(this.getAlgorithm().getName())
// then result = this.getAlgorithm().getName()
// else result = unknownAlgorithm()
// }
// final predicate hasAlgorithm(){
// exists(this.getAlgorithm())
// }
// final predicate isUnknownAlgorithm(){
// this.getAlgorithmName() = unknownAlgorithm()
// or
// not this.hasAlgorithm()
// }
// // TODO: this might have to be parameterized by a configuration source for
// // situations where an operation is passed an algorithm
// abstract CryptographicAlgorithm getAlgorithm();
// }
// /** A key generation operation for asymmetric keys */
// abstract class KeyGen extends CryptographicOperation{
// int getAKeySizeInBits(){
// result = getKeySizeInBits(_)
// }
// final predicate hasKeySize(Expr configSrc){
// exists(this.getKeySizeInBits(configSrc))
// }
// final predicate hasKeySize(){
// exists(this.getAKeySizeInBits())
// }
// abstract Expr getKeyConfigSrc();
// abstract int getKeySizeInBits(Expr configSrc);
// }
abstract class CryptographicOperation extends CryptographicArtifact, Call { }
abstract class KeyGeneration extends CryptographicOperation {
// TODO: what if the algorithm is UNKNOWN?
abstract Expr getKeyConfigurationSource(CryptographicAlgorithm alg);
abstract CryptographicAlgorithm getAlgorithm();
int getKeySizeInBits(CryptographicAlgorithm alg) {
result = this.getKeyConfigurationSource(alg).(Literal).getValue().toInt()
}
predicate hasConstantKeySize(CryptographicAlgorithm alg) { exists(this.getKeySizeInBits(alg)) }
predicate hasKeyConfigurationSource(CryptographicAlgorithm alg) {
exists(this.getKeyConfigurationSource(alg))
}
Expr getAKeyConfigurationSource() { result = this.getKeyConfigurationSource(_) }
}
abstract class AsymmetricKeyGeneration extends KeyGeneration { }
abstract class SymmetricKeyGeneration extends KeyGeneration { }
/**
* A cryptographic algorithm is a `CryptographicArtifact`
* representing a cryptographic algorithm (see `CryptoAlgorithmNames.qll`).
* Cryptographic algorithms can be functions referencing common crypto algorithms (e.g., hashlib.md5)
* or strings that are used in cryptographic operation configurations (e.g., hashlib.new("md5")).
* Cryptogrpahic algorithms may also be operations that wrap or abstract one or
* more algorithms (e.g., cyrptography.fernet.Fernet and AES, CBC and PKCS7).
*
* In principle, this class should model the location where an algorithm enters the program, not
* necessarily where it is used.
*/
abstract class CryptographicAlgorithm extends CryptographicArtifact {
abstract string getName();
abstract string getAlgType();
// string getAlgType(){
// if this instanceof HashAlgorithm then result = getHashType()
// else if this instanceof KeyDerivationAlgorithm then result = getKeyDerivationType()
// else if this instanceof SymmetricEncryptionAlgorithm then result = getSymmetricEncryptionType()
// else if this instanceof AsymmetricEncryptionAlgorithm then result = getAsymmetricEncryptionType()
// else if this instanceof SymmetricEncryptionAlgorithm then result = getSymmetricPaddingType()
// else if this instanceof AsymmetricEncryptionAlgorithm then result = getAsymmetricPaddingType()
// else if this instanceof EllipticCurveAlgorithm then result = getEllipticCurveType()
// else if this instanceof BlockMode then result = getCipherBlockModeType()
// else if this instanceof KeyExchangeAlgorithm then result = getKeyExchangeType()
// else if this instanceof SigningAlgorithm then result = getSignatureType()
// else result = unknownAlgorithm()
// }
// TODO: handle case where name isn't known, not just unknown?
/**
* Normalizes a raw name into a normalized name as found in `CryptoAlgorithmNames.qll`.
* Subclassess should override for more api-specific normalization.
* By deafult, converts a raw name to upper-case with no hyphen, underscore, hash, or space.
*/
bindingset[s]
string normalizeName(string s) {
exists(string normStr | normStr = s.toUpperCase().regexpReplaceAll("[-_ ]|/", "") |
result = normStr and isKnownAlgorithm(result)
or
result = unknownAlgorithm() and not isKnownAlgorithm(normStr)
)
}
abstract Expr configurationSink();
predicate hasConfigurationSink() { exists(this.configurationSink()) }
}
abstract class HashAlgorithm extends CryptographicAlgorithm {
final string getHashName() {
if exists(string n | n = this.getName() and isHashingAlgorithm(n))
then isHashingAlgorithm(result) and result = this.getName()
else result = unknownAlgorithm()
}
override string getAlgType() { result = getHashType() }
}
abstract class KeyDerivationAlgorithm extends CryptographicAlgorithm {
final string getKDFName() {
if exists(string n | n = this.getName() and isKeyDerivationAlgorithm(n))
then isKeyDerivationAlgorithm(result) and result = this.getName()
else result = unknownAlgorithm()
}
override string getAlgType() { result = getKeyDerivationType() }
}
// abstract class KeyDerivationOperation extends CryptographicOperation{
// DataFlow::Node getIterationSizeSrc(){
// none()
// }
// DataFlow::Node getSaltConfigSrc(){
// none()
// }
// DataFlow::Node getHashConfigSrc(){
// none()
// }
// // TODO: get encryption algorithm for CBC-based KDF?
// DataFlow::Node getDerivedKeySizeSrc(){
// none()
// }
// DataFlow::Node getModeSrc(){
// none()
// }
// // TODO: add more to cover all the parameters of most KDF operations? Perhaps subclass for each type?
// abstract predicate requiresIteration();
// abstract predicate requiresSalt();
// abstract predicate requiresHash();
// //abstract predicate requiresKeySize(); // Going to assume all requires a size
// abstract predicate requiresMode();
// }
abstract class EncryptionAlgorithm extends CryptographicAlgorithm {
final predicate isAsymmetric() { this instanceof AsymmetricEncryptionAlgorithm }
final predicate isSymmetric() { not this.isAsymmetric() }
// NOTE: DO_NOT add getEncryptionName here, we rely on the fact the parent
// class does not have this common predicate.
}
/**
* A parent class to represent any algorithm for which
* asymmetric cryptography is involved.
* Intended to be distinct from AsymmetricEncryptionAlgorithm
* which is intended only for asymmetric algorithms that specifically encrypt.
*/
abstract class AsymmetricAlgorithm extends CryptographicAlgorithm { }
/**
* Algorithms directly or indirectly related to asymmetric encryption,
* e.g., RSA, DSA, but also RSA padding algorithms
*/
abstract class AsymmetricEncryptionAlgorithm extends AsymmetricAlgorithm, EncryptionAlgorithm {
final string getEncryptionName() {
if exists(string n | n = this.getName() and isAsymmetricEncryptionAlgorithm(n))
then isAsymmetricEncryptionAlgorithm(result) and result = this.getName()
else result = unknownAlgorithm()
}
override string getAlgType() { result = getAsymmetricEncryptionType() }
}
/**
* Algorithms directly or indirectly related to symmetric encryption,
* e.g., AES, DES, but also block modes and padding
*/
abstract class SymmetricEncryptionAlgorithm extends EncryptionAlgorithm {
final string getEncryptionName() {
if exists(string n | n = this.getName() and isSymmetricEncryptionAlgorithm(n))
then isSymmetricEncryptionAlgorithm(result) and result = this.getName()
else result = unknownAlgorithm()
}
// TODO: add a stream cipher predicate?
override string getAlgType() { result = getSymmetricEncryptionType() }
}
// Used only to categorize all padding into a single object,
// DO_NOT add predicates here. Only for categorization purposes.
abstract class PaddingAlgorithm extends CryptographicAlgorithm { }
abstract class SymmetricPadding extends PaddingAlgorithm {
final string getPaddingName() {
if exists(string n | n = this.getName() and isSymmetricPaddingAlgorithm(n))
then isSymmetricPaddingAlgorithm(result) and result = this.getName()
else result = unknownAlgorithm()
}
override string getAlgType() { result = getSymmetricPaddingType() }
}
abstract class AsymmetricPadding extends PaddingAlgorithm {
final string getPaddingName() {
if exists(string n | n = this.getName() and isAsymmetricPaddingAlgorithm(n))
then isAsymmetricPaddingAlgorithm(result) and result = this.getName()
else result = unknownAlgorithm()
}
override string getAlgType() { result = getAsymmetricPaddingType() }
}
abstract class EllipticCurveAlgorithm extends AsymmetricAlgorithm {
final string getCurveName() {
if exists(string n | n = this.getName() and isEllipticCurveAlgorithm(n))
then isEllipticCurveAlgorithm(result) and result = this.getName()
else result = unknownAlgorithm()
}
final int getCurveBitSize() { isEllipticCurveAlgorithm(this.getCurveName(), result) }
override string getAlgType() { result = getEllipticCurveType() }
}
abstract class BlockModeAlgorithm extends CryptographicAlgorithm {
final string getBlockModeName() {
if exists(string n | n = this.getName() and isCipherBlockModeAlgorithm(n))
then isCipherBlockModeAlgorithm(result) and result = this.getName()
else result = unknownAlgorithm()
}
/**
* Gets the source of the IV configuration.
*/
abstract Expr getIVorNonce();
final predicate hasIVorNonce() { exists(this.getIVorNonce()) }
override string getAlgType() { result = getCipherBlockModeType() }
}
// abstract class KeyWrapOperation extends CryptographicOperation{
// }
abstract class AuthenticatedEncryptionAlgorithm extends SymmetricEncryptionAlgorithm {
final string getAuthticatedEncryptionName() {
if exists(string n | n = this.getName() and isSymmetricEncryptionAlgorithm(n))
then isSymmetricEncryptionAlgorithm(result) and result = this.getName()
else result = unknownAlgorithm()
}
}
abstract class KeyExchangeAlgorithm extends AsymmetricAlgorithm {
final string getKeyExchangeName() {
if exists(string n | n = this.getName() and isKeyExchangeAlgorithm(n))
then isKeyExchangeAlgorithm(result) and result = this.getName()
else result = unknownAlgorithm()
}
override string getAlgType() { result = getKeyExchangeType() }
}
abstract class SigningAlgorithm extends AsymmetricAlgorithm {
final string getSigningName() {
if exists(string n | n = this.getName() and isSignatureAlgorithm(n))
then isSignatureAlgorithm(result) and result = this.getName()
else result = unknownAlgorithm()
}
override string getAlgType() { result = getSignatureType() }
}