Skip to content

Commit 34b2e3e

Browse files
committed
Copy the structure of the Javascript query
1 parent 5c403d3 commit 34b2e3e

File tree

11 files changed

+152
-234
lines changed

11 files changed

+152
-234
lines changed

go/ql/lib/go.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import semmle.go.frameworks.AwsLambda
3333
import semmle.go.frameworks.Beego
3434
import semmle.go.frameworks.BeegoOrm
3535
import semmle.go.frameworks.Bun
36+
import semmle.go.frameworks.CryptoLibraries
3637
import semmle.go.frameworks.RsCors
3738
import semmle.go.frameworks.Couchbase
3839
import semmle.go.frameworks.Echo

go/ql/lib/qlpack.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ extractor: go
66
library: true
77
upgrades: upgrades
88
dependencies:
9+
codeql/concepts: ${workspace}
910
codeql/dataflow: ${workspace}
1011
codeql/mad: ${workspace}
1112
codeql/threat-models: ${workspace}

go/ql/lib/semmle/go/Concepts.qll

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ import go
88
import semmle.go.dataflow.FunctionInputsAndOutputs
99
import semmle.go.concepts.HTTP
1010
import semmle.go.concepts.GeneratedFile
11+
private import codeql.concepts.ConceptsShared
12+
private import semmle.go.dataflow.internal.DataFlowImplSpecific
13+
14+
private module ConceptsShared = ConceptsMake<Location, GoDataFlow>;
1115

1216
/**
1317
* A data-flow node that executes an operating system command,
@@ -505,3 +509,31 @@ module UnmarshalingFunction {
505509
abstract string getFormat();
506510
}
507511
}
512+
513+
/**
514+
* Provides models for cryptographic things.
515+
*/
516+
module Cryptography {
517+
private import ConceptsShared::Cryptography as SC
518+
519+
/**
520+
* A data-flow node that is an application of a cryptographic algorithm. For example,
521+
* encryption, decryption, signature-validation.
522+
*
523+
* Extend this class to refine existing API models. If you want to model new APIs,
524+
* extend `CryptographicOperation::Range` instead.
525+
*/
526+
class CryptographicOperation extends SC::CryptographicOperation { }
527+
528+
class EncryptionAlgorithm = SC::EncryptionAlgorithm;
529+
530+
class HashingAlgorithm = SC::HashingAlgorithm;
531+
532+
class PasswordHashingAlgorithm = SC::PasswordHashingAlgorithm;
533+
534+
module CryptographicOperation = SC::CryptographicOperation;
535+
536+
class BlockMode = SC::BlockMode;
537+
538+
class CryptographicAlgorithm = SC::CryptographicAlgorithm;
539+
}

go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll

Lines changed: 14 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -3,180 +3,31 @@
33
*/
44

55
import go
6+
import semmle.go.Concepts::Cryptography
7+
private import codeql.concepts.internal.CryptoAlgorithmNames
68

79
/**
8-
* Names of cryptographic algorithms, separated into strong and weak variants.
9-
*
10-
* The names are normalized: upper-case, no spaces, dashes or underscores.
11-
*
12-
* The names are inspired by the names used in real world crypto libraries.
13-
*
14-
* The classification into strong and weak are based on OWASP and Wikipedia (2020).
15-
*
16-
* Sources (more links in qhelp file):
17-
* https://en.wikipedia.org/wiki/Strong_cryptography#Cryptographically_strong_algorithms
18-
* https://en.wikipedia.org/wiki/Strong_cryptography#Examples
19-
* https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html
20-
*/
21-
private module AlgorithmNames {
22-
predicate isStrongHashingAlgorithm(string name) {
23-
name =
24-
[
25-
"DSA", "ED25519", "SHA256", "SHA384", "SHA512", "SHA3", "ES256", "ECDSA256", "ES384",
26-
"ECDSA384", "ES512", "ECDSA512", "SHA2", "SHA224"
27-
]
28-
}
29-
30-
predicate isWeakHashingAlgorithm(string name) {
31-
name =
32-
[
33-
"HAVEL128", "MD2", "SHA1", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256",
34-
"RIPEMD320", "SHA0"
35-
]
36-
}
37-
38-
predicate isStrongEncryptionAlgorithm(string name) {
39-
name = ["AES", "AES128", "AES192", "AES256", "AES512", "RSA", "RABBIT", "BLOWFISH"]
40-
}
41-
42-
predicate isWeakEncryptionAlgorithm(string name) {
43-
name =
44-
[
45-
"DES", "3DES", "ARC5", "RC5", "TRIPLEDES", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4",
46-
"RC4", "ARCFOUR"
47-
]
48-
}
49-
50-
predicate isStrongPasswordHashingAlgorithm(string name) {
51-
name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"]
52-
}
53-
54-
predicate isWeakPasswordHashingAlgorithm(string name) { none() }
55-
}
56-
57-
private import AlgorithmNames
58-
59-
/**
60-
* A cryptographic algorithm.
61-
*/
62-
private newtype TCryptographicAlgorithm =
63-
MkHashingAlgorithm(string name, boolean isWeak) {
64-
isStrongHashingAlgorithm(name) and isWeak = false
65-
or
66-
isWeakHashingAlgorithm(name) and isWeak = true
67-
} or
68-
MkEncryptionAlgorithm(string name, boolean isWeak) {
69-
isStrongEncryptionAlgorithm(name) and isWeak = false
70-
or
71-
isWeakEncryptionAlgorithm(name) and isWeak = true
72-
} or
73-
MkPasswordHashingAlgorithm(string name, boolean isWeak) {
74-
isStrongPasswordHashingAlgorithm(name) and isWeak = false
75-
or
76-
isWeakPasswordHashingAlgorithm(name) and isWeak = true
77-
}
78-
79-
/**
80-
* A cryptographic algorithm.
81-
*/
82-
abstract class CryptographicAlgorithm extends TCryptographicAlgorithm {
83-
/** Gets a textual representation of this element. */
84-
string toString() { result = this.getName() }
85-
86-
/**
87-
* Gets the name of this algorithm.
88-
*/
89-
abstract string getName();
90-
91-
/**
92-
* Holds if the name of this algorithm matches `name` modulo case,
93-
* white space, dashes and underscores.
94-
*/
95-
bindingset[name]
96-
predicate matchesName(string name) {
97-
exists(name.regexpReplaceAll("[-_]", "").regexpFind("(?i)\\Q" + this.getName() + "\\E", _, _))
98-
}
99-
100-
/**
101-
* Holds if this algorithm is weak.
102-
*/
103-
abstract predicate isWeak();
104-
}
105-
106-
/**
107-
* A hashing algorithm such as `MD5` or `SHA512`.
108-
*/
109-
class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm {
110-
string name;
111-
boolean isWeak;
112-
113-
HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) }
114-
115-
override string getName() { result = name }
116-
117-
override predicate isWeak() { isWeak = true }
118-
}
119-
120-
/**
121-
* An encryption algorithm such as `DES` or `AES512`.
122-
*/
123-
class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm {
124-
string name;
125-
boolean isWeak;
126-
127-
EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) }
128-
129-
override string getName() { result = name }
130-
131-
override predicate isWeak() { isWeak = true }
132-
}
133-
134-
/**
135-
* A password hashing algorithm such as `PBKDF2` or `SCRYPT`.
136-
*/
137-
class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm {
138-
string name;
139-
boolean isWeak;
140-
141-
PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) }
142-
143-
override string getName() { result = name }
144-
145-
override predicate isWeak() { isWeak = true }
146-
}
147-
148-
/**
149-
* An application of a cryptographic algorithm.
10+
* A cryptographic operation from the `crypto/md5` package.
15011
*/
151-
abstract class CryptographicOperation extends DataFlow::Node {
152-
/**
153-
* Gets the input the algorithm is used on, e.g. the plain text input to be encrypted.
154-
*/
155-
abstract Expr getInput();
12+
private module CryptoMd5 {
13+
private class Md5 extends CryptographicOperation::Range instanceof DataFlow::CallNode {
14+
Md5() { this.getTarget().hasQualifiedName("crypto/md5", ["New", "Sum"]) }
15615

157-
/**
158-
* Gets the applied algorithm.
159-
*/
160-
abstract CryptographicAlgorithm getAlgorithm();
161-
}
16+
override DataFlow::Node getInitialization() { result = this }
16217

163-
/**
164-
* A cryptographic operation from the `crypto/md5` package.
165-
*/
166-
class Md5 extends CryptographicOperation, DataFlow::CallNode {
167-
Md5() { this.getTarget().hasQualifiedName("crypto/md5", ["New", "Sum"]) }
18+
override CryptographicAlgorithm getAlgorithm() { result.matchesName("MD5") }
16819

169-
override Expr getInput() { result = this.getArgument(0).asExpr() }
20+
override DataFlow::Node getAnInput() { result = super.getArgument(0) }
17021

171-
override CryptographicAlgorithm getAlgorithm() {
172-
result.matchesName(this.getTarget().getPackage().getName())
22+
// not relevant for md5
23+
override BlockMode getBlockMode() { none() }
17324
}
17425
}
17526

17627
/**
17728
* A cryptographic operation from the `crypto/sha1` package.
17829
*/
179-
class Sha1 extends CryptographicOperation, DataFlow::CallNode {
30+
class Sha1 extends CryptographicOperation::Range instanceof DataFlow::CallNode {
18031
Sha1() { this.getTarget().hasQualifiedName("crypto/sha1", ["New", "Sum"]) }
18132

18233
override Expr getInput() { result = this.getArgument(0).asExpr() }
@@ -189,7 +40,7 @@ class Sha1 extends CryptographicOperation, DataFlow::CallNode {
18940
/**
19041
* A cryptographic operation from the `crypto/des` package.
19142
*/
192-
class Des extends CryptographicOperation, DataFlow::CallNode {
43+
class Des extends CryptographicOperation::Range instanceof DataFlow::CallNode {
19344
Des() { this.getTarget().hasQualifiedName("crypto/des", ["NewCipher", "NewTripleDESCipher"]) }
19445

19546
override Expr getInput() { result = this.getArgument(0).asExpr() }
@@ -202,7 +53,7 @@ class Des extends CryptographicOperation, DataFlow::CallNode {
20253
/**
20354
* A cryptographic operation from the `crypto/rc4` package.
20455
*/
205-
class Rc4 extends CryptographicOperation, DataFlow::CallNode {
56+
class Rc4 extends CryptographicOperation::Range instanceof DataFlow::CallNode {
20657
Rc4() { this.getTarget().hasQualifiedName("crypto/rc4", "NewCipher") }
20758

20859
override Expr getInput() { result = this.getArgument(0).asExpr() }
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* Provides default sources, sinks and sanitizers for reasoning about
3+
* sensitive information in weak cryptographic algorithms,
4+
* as well as extension points for adding your own.
5+
*/
6+
7+
import go
8+
private import semmle.go.security.SensitiveActions
9+
10+
/**
11+
* Provides default sources, sinks and sanitizers for reasoning about
12+
* sensitive information in weak cryptographic algorithms,
13+
* as well as extension points for adding your own.
14+
*/
15+
module BrokenCryptoAlgorithm {
16+
/**
17+
* A data flow source for sensitive information in broken or weak cryptographic algorithms.
18+
*/
19+
abstract class Source extends DataFlow::Node { }
20+
21+
/**
22+
* A data flow sink for sensitive information in broken or weak cryptographic algorithms.
23+
*/
24+
abstract class Sink extends DataFlow::Node {
25+
/** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */
26+
abstract DataFlow::Node getInitialization();
27+
}
28+
29+
/**
30+
* A sanitizer for sensitive information in broken or weak cryptographic algorithms.
31+
*/
32+
abstract class Sanitizer extends DataFlow::Node { }
33+
34+
/**
35+
* A sensitive source.
36+
*/
37+
class SensitiveSource extends Source {
38+
SensitiveSource() { this.asExpr() instanceof SensitiveExpr }
39+
}
40+
41+
/**
42+
* An expression used by a broken or weak cryptographic algorithm.
43+
*/
44+
class WeakCryptographicOperationSink extends Sink {
45+
CryptographicOperation application;
46+
47+
WeakCryptographicOperationSink() {
48+
(
49+
application.getAlgorithm().isWeak()
50+
or
51+
application.getBlockMode().isWeak()
52+
) and
53+
this = application.getAnInput()
54+
}
55+
56+
override DataFlow::Node getInitialization() { result = application.getInitialization() }
57+
}
58+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Provides a taint tracking configuration for reasoning about
3+
* sensitive information in broken or weak cryptographic algorithms.
4+
*
5+
* Note, for performance reasons: only import this file if
6+
* `BrokenCryptoAlgorithm::Configuration` is needed, otherwise
7+
* `BrokenCryptoAlgorithmCustomizations` should be imported instead.
8+
*/
9+
10+
import go
11+
import BrokenCryptoAlgorithmCustomizations::BrokenCryptoAlgorithm
12+
13+
/**
14+
* A taint tracking configuration for sensitive information in broken or weak cryptographic algorithms.
15+
*
16+
* This configuration identifies flows from `Source`s, which are sources of
17+
* sensitive data, to `Sink`s, which is an abstract class representing all
18+
* the places sensitive data may used in broken or weak cryptographic algorithms. Additional sources or sinks can be
19+
* added either by extending the relevant class, or by subclassing this configuration itself,
20+
* and amending the sources and sinks.
21+
*/
22+
private module BrokenCryptoAlgorithmConfig implements DataFlow::ConfigSig {
23+
predicate isSource(DataFlow::Node source) { source instanceof Source }
24+
25+
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
26+
27+
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
28+
29+
predicate observeDiffInformedIncrementalMode() { any() }
30+
31+
Location getASelectedSinkLocation(DataFlow::Node sink) {
32+
result = sink.(Sink).getLocation()
33+
or
34+
result = sink.(Sink).getInitialization().getLocation()
35+
}
36+
}
37+
38+
/**
39+
* Taint tracking flow for sensitive information in broken or weak cryptographic algorithms.
40+
*/
41+
module BrokenCryptoAlgorithmFlow = TaintTracking::Global<BrokenCryptoAlgorithmConfig>;

0 commit comments

Comments
 (0)