Skip to content

Commit bdb2d8b

Browse files
committed
Ruby: split OpenSSL parts from CryptoALgorithms.qll and sync with JS/Python version
1 parent 0303c27 commit bdb2d8b

File tree

9 files changed

+383
-351
lines changed

9 files changed

+383
-351
lines changed

config/identical-files.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -452,9 +452,10 @@
452452
"ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImplCommon.qll",
453453
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll"
454454
],
455-
"CryptoAlgorithms Python/JS": [
455+
"CryptoAlgorithms Python/JS/Ruby": [
456456
"javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll",
457-
"python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll"
457+
"python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll",
458+
"ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll"
458459
],
459460
"SensitiveDataHeuristics Python/JS": [
460461
"javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll",

javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
*
1414
* The classification into strong and weak are based on Wikipedia, OWASP and google (2017).
1515
*/
16-
private module AlgorithmNames {
16+
module AlgorithmNames {
17+
predicate isStrongBlockMode(string name) { name = ["CCM", "GCM"] }
18+
19+
predicate isWeakBlockMode(string name) { name = "ECB" }
20+
1721
predicate isStrongHashingAlgorithm(string name) {
1822
name =
1923
[
@@ -31,14 +35,20 @@ private module AlgorithmNames {
3135
}
3236

3337
predicate isStrongEncryptionAlgorithm(string name) {
34-
name = ["AES", "AES128", "AES192", "AES256", "AES512", "RSA", "RABBIT", "BLOWFISH"]
38+
name =
39+
[
40+
"AES", "AES128", "AES192", "AES256", "AES512", "AES-128", "AES-192", "AES-256", "AES-512",
41+
"RSA", "RABBIT", "BLOWFISH", "BF", "ECIES", "CAST", "CAST5", "CAMELLIA", "CAMELLIA128",
42+
"CAMELLIA192", "CAMELLIA256", "CAMELLIA-128", "CAMELLIA-192", "CAMELLIA-256", "CHACHA",
43+
"GOST", "GOST89"
44+
]
3545
}
3646

3747
predicate isWeakEncryptionAlgorithm(string name) {
3848
name =
3949
[
40-
"DES", "3DES", "TRIPLEDES", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4", "ARCFOUR",
41-
"ARC5", "RC5"
50+
"DES", "3DES", "DES3", "TRIPLEDES", "DESX", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4",
51+
"RC4", "ARCFOUR", "ARC5", "RC5"
4252
]
4353
}
4454

python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
*
1414
* The classification into strong and weak are based on Wikipedia, OWASP and google (2017).
1515
*/
16-
private module AlgorithmNames {
16+
module AlgorithmNames {
17+
predicate isStrongBlockMode(string name) { name = ["CCM", "GCM"] }
18+
19+
predicate isWeakBlockMode(string name) { name = "ECB" }
20+
1721
predicate isStrongHashingAlgorithm(string name) {
1822
name =
1923
[
@@ -31,14 +35,20 @@ private module AlgorithmNames {
3135
}
3236

3337
predicate isStrongEncryptionAlgorithm(string name) {
34-
name = ["AES", "AES128", "AES192", "AES256", "AES512", "RSA", "RABBIT", "BLOWFISH"]
38+
name =
39+
[
40+
"AES", "AES128", "AES192", "AES256", "AES512", "AES-128", "AES-192", "AES-256", "AES-512",
41+
"RSA", "RABBIT", "BLOWFISH", "BF", "ECIES", "CAST", "CAST5", "CAMELLIA", "CAMELLIA128",
42+
"CAMELLIA192", "CAMELLIA256", "CAMELLIA-128", "CAMELLIA-192", "CAMELLIA-256", "CHACHA",
43+
"GOST", "GOST89"
44+
]
3545
}
3646

3747
predicate isWeakEncryptionAlgorithm(string name) {
3848
name =
3949
[
40-
"DES", "3DES", "TRIPLEDES", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4", "ARCFOUR",
41-
"ARC5", "RC5"
50+
"DES", "3DES", "DES3", "TRIPLEDES", "DESX", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4",
51+
"RC4", "ARCFOUR", "ARC5", "RC5"
4252
]
4353
}
4454

ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll

Lines changed: 1 addition & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
* The classification into strong and weak are based on Wikipedia, OWASP and google (2017).
1515
*/
16-
private module AlgorithmNames {
16+
module AlgorithmNames {
1717
predicate isStrongBlockMode(string name) { name = ["CCM", "GCM"] }
1818

1919
predicate isWeakBlockMode(string name) { name = "ECB" }
@@ -59,128 +59,7 @@ private module AlgorithmNames {
5959
predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" }
6060
}
6161

62-
bindingset[algorithmString]
63-
private string algorithmRegex(string algorithmString) {
64-
// Algorithms usually appear in names surrounded by characters that are not
65-
// alphabetical characters in the same case. This handles the upper and lower
66-
// case cases.
67-
result =
68-
"((^|.*[^A-Z])(" + algorithmString + ")([^A-Z].*|$))" +
69-
// or...
70-
"|" +
71-
// For lowercase, we want to be careful to avoid being confused by camelCase
72-
// hence we require two preceding uppercase letters to be sure of a case switch,
73-
// or a preceding non-alphabetic character
74-
"((^|.*[A-Z]{2}|.*[^a-zA-Z])(" + algorithmString.toLowerCase() + ")([^a-z].*|$))"
75-
}
76-
77-
private module OpenSSL {
78-
/**
79-
* A known `OpenSSL::Cipher`. Supported ciphers depend on the version of
80-
* `OpenSSL` installed on a system. In the general case, a name will include
81-
* the cipher name, the key length, and the block encryption mode.
82-
*
83-
* Note that since the cipher name itself always comes first in these names
84-
* and always uses a "-" to demark to block mode, we can safely uppercase
85-
* these names when checking against an `algorithmRegex`.
86-
*
87-
* See https://ruby-doc.org/stdlib-3.0.1/libdoc/openssl/rdoc/OpenSSL/Cipher.html
88-
*/
89-
predicate isOpenSSLCipher(string name) {
90-
name =
91-
[
92-
"AES-128-CBC", "AES-128-CBC-HMAC-SHA1", "AES-128-CFB", "AES-128-CFB1", "AES-128-CFB8",
93-
"AES-128-CTR", "AES-128-ECB", "AES-128-OFB", "AES-128-XTS", "AES-192-CBC", "AES-192-CFB",
94-
"AES-192-CFB1", "AES-192-CFB8", "AES-192-CTR", "AES-192-ECB", "AES-192-OFB", "AES-256-CBC",
95-
"AES-256-CBC-HMAC-SHA1", "AES-256-CFB", "AES-256-CFB1", "AES-256-CFB8", "AES-256-CTR",
96-
"AES-256-ECB", "AES-256-OFB", "AES-256-XTS", "AES128", "AES192", "AES256", "BF", "BF-CBC",
97-
"BF-CFB", "BF-ECB", "BF-OFB", "CAMELLIA-128-CBC", "CAMELLIA-128-CFB", "CAMELLIA-128-CFB1",
98-
"CAMELLIA-128-CFB8", "CAMELLIA-128-ECB", "CAMELLIA-128-OFB", "CAMELLIA-192-CBC",
99-
"CAMELLIA-192-CFB", "CAMELLIA-192-CFB1", "CAMELLIA-192-CFB8", "CAMELLIA-192-ECB",
100-
"CAMELLIA-192-OFB", "CAMELLIA-256-CBC", "CAMELLIA-256-CFB", "CAMELLIA-256-CFB1",
101-
"CAMELLIA-256-CFB8", "CAMELLIA-256-ECB", "CAMELLIA-256-OFB", "CAMELLIA128", "CAMELLIA192",
102-
"CAMELLIA256", "CAST", "CAST-cbc", "CAST5-CBC", "CAST5-CFB", "CAST5-ECB", "CAST5-OFB",
103-
"ChaCha", "DES", "DES-CBC", "DES-CFB", "DES-CFB1", "DES-CFB8", "DES-ECB", "DES-EDE",
104-
"DES-EDE-CBC", "DES-EDE-CFB", "DES-EDE-OFB", "DES-EDE3", "DES-EDE3-CBC", "DES-EDE3-CFB",
105-
"DES-EDE3-CFB1", "DES-EDE3-CFB8", "DES-EDE3-OFB", "DES-OFB", "DES3", "DESX", "DESX-CBC",
106-
"GOST 28147-89", "RC2", "RC2-40-CBC", "RC2-64-CBC", "RC2-CBC", "RC2-CFB", "RC2-ECB",
107-
"RC2-OFB", "RC4", "RC4-40", "RC4-HMAC-MD5", "aes-128-cbc", "aes-128-cbc-hmac-sha1",
108-
"aes-128-cfb", "aes-128-cfb1", "aes-128-cfb8", "aes-128-ctr", "aes-128-ecb", "aes-128-gcm",
109-
"aes-128-ofb", "aes-128-xts", "aes-192-cbc", "aes-192-cfb", "aes-192-cfb1", "aes-192-cfb8",
110-
"aes-192-ctr", "aes-192-ecb", "aes-192-gcm", "aes-192-ofb", "aes-256-cbc",
111-
"aes-256-cbc-hmac-sha1", "aes-256-cfb", "aes-256-cfb1", "aes-256-cfb8", "aes-256-ctr",
112-
"aes-256-ecb", "aes-256-gcm", "aes-256-ofb", "aes-256-xts", "aes128", "aes192", "aes256",
113-
"bf", "bf-cbc", "bf-cfb", "bf-ecb", "bf-ofb", "blowfish", "camellia-128-cbc",
114-
"camellia-128-cfb", "camellia-128-cfb1", "camellia-128-cfb8", "camellia-128-ecb",
115-
"camellia-128-ofb", "camellia-192-cbc", "camellia-192-cfb", "camellia-192-cfb1",
116-
"camellia-192-cfb8", "camellia-192-ecb", "camellia-192-ofb", "camellia-256-cbc",
117-
"camellia-256-cfb", "camellia-256-cfb1", "camellia-256-cfb8", "camellia-256-ecb",
118-
"camellia-256-ofb", "camellia128", "camellia192", "camellia256", "cast", "cast-cbc",
119-
"cast5-cbc", "cast5-cfb", "cast5-ecb", "cast5-ofb", "chacha", "des", "des-cbc", "des-cfb",
120-
"des-cfb1", "des-cfb8", "des-ecb", "des-ede", "des-ede-cbc", "des-ede-cfb", "des-ede-ofb",
121-
"des-ede3", "des-ede3-cbc", "des-ede3-cfb", "des-ede3-cfb1", "des-ede3-cfb8",
122-
"des-ede3-ofb", "des-ofb", "des3", "desx", "desx-cbc", "gost89", "gost89-cnt", "gost89-ecb",
123-
"id-aes128-GCM", "id-aes192-GCM", "id-aes256-GCM", "rc2", "rc2-40-cbc", "rc2-64-cbc",
124-
"rc2-cbc", "rc2-cfb", "rc2-ecb", "rc2-ofb", "rc4", "rc4-40", "rc4-hmac-md5"
125-
]
126-
}
127-
128-
predicate isWeakOpenSSLCipher(string name) {
129-
isOpenSSLCipher(name) and
130-
name.toUpperCase().regexpMatch(getInsecureAlgorithmRegex())
131-
}
132-
133-
predicate isStrongOpenSSLCipher(string name) {
134-
isOpenSSLCipher(name) and
135-
name.toUpperCase().regexpMatch(getSecureAlgorithmRegex()) and
136-
// exclude algorithms that include a weak component
137-
not name.toUpperCase().regexpMatch(getInsecureAlgorithmRegex())
138-
}
139-
}
140-
14162
private import AlgorithmNames
142-
private import OpenSSL
143-
144-
private string rankedInsecureAlgorithm(int i) {
145-
// In this case we know these are being used for encryption, so we want to match
146-
// weak hash algorithms and block modes as well.
147-
result =
148-
rank[i](string s |
149-
isWeakEncryptionAlgorithm(s) or isWeakHashingAlgorithm(s) or isWeakBlockMode(s)
150-
)
151-
}
152-
153-
private string insecureAlgorithmString(int i) {
154-
i = 1 and result = rankedInsecureAlgorithm(i)
155-
or
156-
result = rankedInsecureAlgorithm(i) + "|" + insecureAlgorithmString(i - 1)
157-
}
158-
159-
/**
160-
* Gets the regular expression used for matching strings that look like they
161-
* contain an algorithm that is known to be insecure.
162-
*/
163-
private string getInsecureAlgorithmRegex() {
164-
result = algorithmRegex(insecureAlgorithmString(max(int i | exists(rankedInsecureAlgorithm(i)))))
165-
}
166-
167-
private string rankedSecureAlgorithm(int i) {
168-
result = rank[i](string s | isStrongEncryptionAlgorithm(s))
169-
}
170-
171-
private string secureAlgorithmString(int i) {
172-
i = 1 and result = rankedSecureAlgorithm(i)
173-
or
174-
result = rankedSecureAlgorithm(i) + "|" + secureAlgorithmString(i - 1)
175-
}
176-
177-
/**
178-
* Gets a regular expression for matching strings that look like they
179-
* contain an algorithm that is known to be secure.
180-
*/
181-
string getSecureAlgorithmRegex() {
182-
result = algorithmRegex(secureAlgorithmString(max(int i | exists(rankedSecureAlgorithm(i)))))
183-
}
18463

18564
/**
18665
* A cryptographic algorithm.
@@ -200,11 +79,6 @@ private newtype TCryptographicAlgorithm =
20079
isStrongPasswordHashingAlgorithm(name) and isWeak = false
20180
or
20281
isWeakPasswordHashingAlgorithm(name) and isWeak = true
203-
} or
204-
MkOpenSSLCipher(string name, boolean isWeak) {
205-
isStrongOpenSSLCipher(name) and isWeak = false
206-
or
207-
isWeakOpenSSLCipher(name) and isWeak = true
20882
}
20983

21084
/**
@@ -277,18 +151,3 @@ class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, Cryptographic
277151

278152
override predicate isWeak() { isWeak = true }
279153
}
280-
281-
/**
282-
* A known OpenSSL cipher. This may include information about the block
283-
* encryption mode, which can affect if the cipher is marked as being weak.
284-
*/
285-
class OpenSSLCipher extends MkOpenSSLCipher, CryptographicAlgorithm {
286-
string name;
287-
boolean isWeak;
288-
289-
OpenSSLCipher() { this = MkOpenSSLCipher(name, isWeak) }
290-
291-
override string getName() { result = name }
292-
293-
override predicate isWeak() { isWeak = true }
294-
}

0 commit comments

Comments
 (0)