Skip to content

Commit e6bc45e

Browse files
committed
Ruby: Base OpenSSL supported algorithms on OpenSSL 1.1.1 and LibreSSL 3.4.1
1 parent d3af687 commit e6bc45e

File tree

1 file changed

+192
-37
lines changed

1 file changed

+192
-37
lines changed

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

Lines changed: 192 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/**
2+
* Provides classes modeling parts of the Ruby `OpenSSL` library, which wraps
3+
* the OpenSSL C library.
4+
*/
5+
16
private import CryptoAlgorithms::AlgorithmNames
27

38
bindingset[algorithmString]
@@ -56,11 +61,14 @@ string getSecureAlgorithmRegex() {
5661
result = algorithmRegex(secureAlgorithmString(max(int i | exists(rankedSecureAlgorithm(i)))))
5762
}
5863

59-
private module Ciphers {
64+
module Ciphers {
6065
/**
61-
* A known `OpenSSL::Cipher`. Supported ciphers depend on the version of
62-
* `OpenSSL` installed on a system. In the general case, a name will include
63-
* the cipher name, the key length, and the block encryption mode.
66+
* Holds if `name` is a known `OpenSSL::Cipher`. Supported ciphers depend on the
67+
* version of `OpenSSL` or `LibreSSL` specified when installing the `openssl` gem.
68+
* Ciphers listed here are sourced from OpenSSL 1.1.1 and LibreSSL 3.4.1.
69+
*
70+
* In the general case, a name will include the cipher name, the key length,
71+
* and the block encryption mode.
6472
*
6573
* Note that since the cipher name itself always comes first in these names
6674
* and always uses a "-" to demark to block mode, we can safely uppercase
@@ -71,47 +79,184 @@ private module Ciphers {
7179
predicate isOpenSSLCipher(string name) {
7280
name =
7381
[
74-
"AES-128-CBC", "AES-128-CBC-HMAC-SHA1", "AES-128-CFB", "AES-128-CFB1", "AES-128-CFB8",
75-
"AES-128-CTR", "AES-128-ECB", "AES-128-OFB", "AES-128-XTS", "AES-192-CBC", "AES-192-CFB",
76-
"AES-192-CFB1", "AES-192-CFB8", "AES-192-CTR", "AES-192-ECB", "AES-192-OFB", "AES-256-CBC",
77-
"AES-256-CBC-HMAC-SHA1", "AES-256-CFB", "AES-256-CFB1", "AES-256-CFB8", "AES-256-CTR",
78-
"AES-256-ECB", "AES-256-OFB", "AES-256-XTS", "AES128", "AES192", "AES256", "BF", "BF-CBC",
79-
"BF-CFB", "BF-ECB", "BF-OFB", "CAMELLIA-128-CBC", "CAMELLIA-128-CFB", "CAMELLIA-128-CFB1",
80-
"CAMELLIA-128-CFB8", "CAMELLIA-128-ECB", "CAMELLIA-128-OFB", "CAMELLIA-192-CBC",
81-
"CAMELLIA-192-CFB", "CAMELLIA-192-CFB1", "CAMELLIA-192-CFB8", "CAMELLIA-192-ECB",
82-
"CAMELLIA-192-OFB", "CAMELLIA-256-CBC", "CAMELLIA-256-CFB", "CAMELLIA-256-CFB1",
83-
"CAMELLIA-256-CFB8", "CAMELLIA-256-ECB", "CAMELLIA-256-OFB", "CAMELLIA128", "CAMELLIA192",
84-
"CAMELLIA256", "CAST", "CAST-cbc", "CAST5-CBC", "CAST5-CFB", "CAST5-ECB", "CAST5-OFB",
85-
"ChaCha", "DES", "DES-CBC", "DES-CFB", "DES-CFB1", "DES-CFB8", "DES-ECB", "DES-EDE",
86-
"DES-EDE-CBC", "DES-EDE-CFB", "DES-EDE-OFB", "DES-EDE3", "DES-EDE3-CBC", "DES-EDE3-CFB",
87-
"DES-EDE3-CFB1", "DES-EDE3-CFB8", "DES-EDE3-OFB", "DES-OFB", "DES3", "DESX", "DESX-CBC",
88-
"GOST 28147-89", "RC2", "RC2-40-CBC", "RC2-64-CBC", "RC2-CBC", "RC2-CFB", "RC2-ECB",
89-
"RC2-OFB", "RC4", "RC4-40", "RC4-HMAC-MD5", "aes-128-cbc", "aes-128-cbc-hmac-sha1",
82+
"aes-128-cbc", "aes-128-cbc-hmac-sha1", "aes-128-cbc-hmac-sha256", "aes-128-ccm",
9083
"aes-128-cfb", "aes-128-cfb1", "aes-128-cfb8", "aes-128-ctr", "aes-128-ecb", "aes-128-gcm",
91-
"aes-128-ofb", "aes-128-xts", "aes-192-cbc", "aes-192-cfb", "aes-192-cfb1", "aes-192-cfb8",
92-
"aes-192-ctr", "aes-192-ecb", "aes-192-gcm", "aes-192-ofb", "aes-256-cbc",
93-
"aes-256-cbc-hmac-sha1", "aes-256-cfb", "aes-256-cfb1", "aes-256-cfb8", "aes-256-ctr",
94-
"aes-256-ecb", "aes-256-gcm", "aes-256-ofb", "aes-256-xts", "aes128", "aes192", "aes256",
95-
"bf", "bf-cbc", "bf-cfb", "bf-ecb", "bf-ofb", "blowfish", "camellia-128-cbc",
96-
"camellia-128-cfb", "camellia-128-cfb1", "camellia-128-cfb8", "camellia-128-ecb",
97-
"camellia-128-ofb", "camellia-192-cbc", "camellia-192-cfb", "camellia-192-cfb1",
98-
"camellia-192-cfb8", "camellia-192-ecb", "camellia-192-ofb", "camellia-256-cbc",
99-
"camellia-256-cfb", "camellia-256-cfb1", "camellia-256-cfb8", "camellia-256-ecb",
100-
"camellia-256-ofb", "camellia128", "camellia192", "camellia256", "cast", "cast-cbc",
101-
"cast5-cbc", "cast5-cfb", "cast5-ecb", "cast5-ofb", "chacha", "des", "des-cbc", "des-cfb",
102-
"des-cfb1", "des-cfb8", "des-ecb", "des-ede", "des-ede-cbc", "des-ede-cfb", "des-ede-ofb",
103-
"des-ede3", "des-ede3-cbc", "des-ede3-cfb", "des-ede3-cfb1", "des-ede3-cfb8",
104-
"des-ede3-ofb", "des-ofb", "des3", "desx", "desx-cbc", "gost89", "gost89-cnt", "gost89-ecb",
105-
"id-aes128-GCM", "id-aes192-GCM", "id-aes256-GCM", "rc2", "rc2-40-cbc", "rc2-64-cbc",
106-
"rc2-cbc", "rc2-cfb", "rc2-ecb", "rc2-ofb", "rc4", "rc4-40", "rc4-hmac-md5"
84+
"aes-128-ocb", "aes-128-ofb", "aes-128-xts", "aes-192-cbc", "aes-192-ccm", "aes-192-cfb",
85+
"aes-192-cfb1", "aes-192-cfb8", "aes-192-ctr", "aes-192-ecb", "aes-192-gcm", "aes-192-ocb",
86+
"aes-192-ofb", "aes-256-cbc", "aes-256-cbc-hmac-sha1", "aes-256-cbc-hmac-sha256",
87+
"aes-256-ccm", "aes-256-cfb", "aes-256-cfb1", "aes-256-cfb8", "aes-256-ctr", "aes-256-ecb",
88+
"aes-256-gcm", "aes-256-ocb", "aes-256-ofb", "aes-256-xts", "aes128", "aes192", "aes256",
89+
"aria-128-cbc", "aria-128-ccm", "aria-128-cfb", "aria-128-cfb1", "aria-128-cfb8",
90+
"aria-128-ctr", "aria-128-ecb", "aria-128-gcm", "aria-128-ofb", "aria-192-cbc",
91+
"aria-192-ccm", "aria-192-cfb", "aria-192-cfb1", "aria-192-cfb8", "aria-192-ctr",
92+
"aria-192-ecb", "aria-192-gcm", "aria-192-ofb", "aria-256-cbc", "aria-256-ccm",
93+
"aria-256-cfb", "aria-256-cfb1", "aria-256-cfb8", "aria-256-ctr", "aria-256-ecb",
94+
"aria-256-gcm", "aria-256-ofb", "aria128", "aria192", "aria256", "bf", "bf-cbc", "bf-cfb",
95+
"bf-ecb", "bf-ofb", "blowfish", "camellia-128-cbc", "camellia-128-cfb", "camellia-128-cfb1",
96+
"camellia-128-cfb8", "camellia-128-ctr", "camellia-128-ecb", "camellia-128-ofb",
97+
"camellia-192-cbc", "camellia-192-cfb", "camellia-192-cfb1", "camellia-192-cfb8",
98+
"camellia-192-ctr", "camellia-192-ecb", "camellia-192-ofb", "camellia-256-cbc",
99+
"camellia-256-cfb", "camellia-256-cfb1", "camellia-256-cfb8", "camellia-256-ctr",
100+
"camellia-256-ecb", "camellia-256-ofb", "camellia128", "camellia192", "camellia256", "cast",
101+
"cast-cbc", "cast5-cbc", "cast5-cfb", "cast5-ecb", "cast5-ofb", "chacha20",
102+
"chacha20-poly1305", "des", "des-cbc", "des-cfb", "des-cfb1", "des-cfb8", "des-ecb",
103+
"des-ede", "des-ede-cbc", "des-ede-cfb", "des-ede-ecb", "des-ede-ofb", "des-ede3",
104+
"des-ede3-cbc", "des-ede3-cfb", "des-ede3-cfb1", "des-ede3-cfb8", "des-ede3-ecb",
105+
"des-ede3-ofb", "des-ofb", "des3", "desx", "desx-cbc", "id-aes128-CCM", "id-aes128-GCM",
106+
"id-aes192-CCM", "id-aes192-GCM", "id-aes256-CCM", "id-aes256-GCM", "idea", "idea-cbc",
107+
"idea-cfb", "idea-ecb", "idea-ofb", "rc2", "rc2-128", "rc2-40", "rc2-40-cbc", "rc2-64",
108+
"rc2-64-cbc", "rc2-cbc", "rc2-cfb", "rc2-ecb", "rc2-ofb", "rc4", "rc4-40", "rc4-hmac-md5",
109+
"seed", "seed-cbc", "seed-cfb", "seed-ecb", "seed-ofb", "sm4", "sm4-cbc", "sm4-cfb",
110+
"sm4-ctr", "sm4-ecb", "sm4-ofb", "AES-128-CBC", "AES-128-CBC-HMAC-SHA1", "AES-128-CFB",
111+
"AES-128-CFB1", "AES-128-CFB8", "AES-128-CTR", "AES-128-ECB", "AES-128-OFB", "AES-128-XTS",
112+
"AES-192-CBC", "AES-192-CFB", "AES-192-CFB1", "AES-192-CFB8", "AES-192-CTR", "AES-192-ECB",
113+
"AES-192-OFB", "AES-256-CBC", "AES-256-CBC-HMAC-SHA1", "AES-256-CFB", "AES-256-CFB1",
114+
"AES-256-CFB8", "AES-256-CTR", "AES-256-ECB", "AES-256-OFB", "AES-256-XTS", "AES128",
115+
"AES192", "AES256", "BF", "BF-CBC", "BF-CFB", "BF-ECB", "BF-OFB", "CAMELLIA-128-CBC",
116+
"CAMELLIA-128-CFB", "CAMELLIA-128-CFB1", "CAMELLIA-128-CFB8", "CAMELLIA-128-ECB",
117+
"CAMELLIA-128-OFB", "CAMELLIA-192-CBC", "CAMELLIA-192-CFB", "CAMELLIA-192-CFB1",
118+
"CAMELLIA-192-CFB8", "CAMELLIA-192-ECB", "CAMELLIA-192-OFB", "CAMELLIA-256-CBC",
119+
"CAMELLIA-256-CFB", "CAMELLIA-256-CFB1", "CAMELLIA-256-CFB8", "CAMELLIA-256-ECB",
120+
"CAMELLIA-256-OFB", "CAMELLIA128", "CAMELLIA192", "CAMELLIA256", "CAST", "CAST-cbc",
121+
"CAST5-CBC", "CAST5-CFB", "CAST5-ECB", "CAST5-OFB", "ChaCha", "DES", "DES-CBC", "DES-CFB",
122+
"DES-CFB1", "DES-CFB8", "DES-ECB", "DES-EDE", "DES-EDE-CBC", "DES-EDE-CFB", "DES-EDE-OFB",
123+
"DES-EDE3", "DES-EDE3-CBC", "DES-EDE3-CFB", "DES-EDE3-CFB1", "DES-EDE3-CFB8",
124+
"DES-EDE3-OFB", "DES-OFB", "DES3", "DESX", "DESX-CBC", "GOST 28147-89", "IDEA", "IDEA-CBC",
125+
"IDEA-CFB", "IDEA-ECB", "IDEA-OFB", "RC2", "RC2-40-CBC", "RC2-64-CBC", "RC2-CBC", "RC2-CFB",
126+
"RC2-ECB", "RC2-OFB", "RC4", "RC4-40", "RC4-HMAC-MD5", "SM4", "SM4-CBC", "SM4-CFB",
127+
"SM4-CTR", "SM4-ECB", "SM4-OFB", "chacha", "gost89", "gost89-cnt", "gost89-ecb"
107128
]
108129
}
109130

131+
/**
132+
* Gets the canonical cipher name in cases where this isn't simply an
133+
* upcased version of the provided name. This may be because a default block
134+
* mode is appended, or due to some other normalization.
135+
*/
136+
private string getSpecialCanonicalCipherName(string name) {
137+
name = "AES128" and result = "AES-128-CBC"
138+
or
139+
name = "AES192" and result = "AES-192-CBC"
140+
or
141+
name = "AES256" and result = "AES-256-CBC"
142+
or
143+
name = "BF" and result = "BF-CBC"
144+
or
145+
name = "CAMELLIA128" and result = "CAMELLIA-128-CBC"
146+
or
147+
name = "CAMELLIA192" and result = "CAMELLIA-192-CBC"
148+
or
149+
name = "CAMELLIA256" and result = "CAMELLIA-256-CBC"
150+
or
151+
name = "CAST" and result = "CAST5-CBC"
152+
or
153+
name = "CAST-cbc" and result = "CAST5-CBC"
154+
or
155+
name = "ChaCha" and result = "ChaCha"
156+
or
157+
name = "DES" and result = "DES-CBC"
158+
or
159+
name = "DES3" and result = "DES-EDE3-CBC"
160+
or
161+
name = "DESX" and result = "DESX-CBC"
162+
or
163+
name = "GOST 28147-89" and result = "gost89"
164+
or
165+
name = "IDEA" and result = "IDEA-CBC"
166+
or
167+
name = "RC2" and result = "RC2-CBC"
168+
or
169+
name = "SM4" and result = "SM4-CBC"
170+
or
171+
name = "aes-128-ccm" and result = "id-aes128-CCM"
172+
or
173+
name = "aes-128-gcm" and result = "id-aes128-GCM"
174+
or
175+
name = "aes-192-ccm" and result = "id-aes192-CCM"
176+
or
177+
name = "aes-192-gcm" and result = "id-aes192-GCM"
178+
or
179+
name = "aes-256-ccm" and result = "id-aes256-CCM"
180+
or
181+
name = "aes-256-gcm" and result = "id-aes256-GCM"
182+
or
183+
name = "aes128" and result = "AES-128-CBC"
184+
or
185+
name = "aes192" and result = "AES-192-CBC"
186+
or
187+
name = "aes256" and result = "AES-256-CBC"
188+
or
189+
name = "bf" and result = "BF-CBC"
190+
or
191+
name = "blowfish" and result = "BF-CBC"
192+
or
193+
name = "camellia128" and result = "CAMELLIA-128-CBC"
194+
or
195+
name = "camellia192" and result = "CAMELLIA-192-CBC"
196+
or
197+
name = "camellia256" and result = "CAMELLIA-256-CBC"
198+
or
199+
name = "cast" and result = "CAST5-CBC"
200+
or
201+
name = "cast-cbc" and result = "CAST5-CBC"
202+
or
203+
name = "chacha" and result = "ChaCha"
204+
or
205+
name = "des" and result = "DES-CBC"
206+
or
207+
name = "des3" and result = "DES-EDE3-CBC"
208+
or
209+
name = "desx" and result = "DESX-CBC"
210+
or
211+
name = "gost89" and result = "gost89"
212+
or
213+
name = "gost89-cnt" and result = "gost89-cnt"
214+
or
215+
name = "gost89-ecb" and result = "gost89-ecb"
216+
or
217+
name = "id-aes128-CCM" and result = "id-aes128-CCM"
218+
or
219+
name = "id-aes128-GCM" and result = "id-aes128-GCM"
220+
or
221+
name = "id-aes192-CCM" and result = "id-aes192-CCM"
222+
or
223+
name = "id-aes192-GCM" and result = "id-aes192-GCM"
224+
or
225+
name = "id-aes256-CCM" and result = "id-aes256-CCM"
226+
or
227+
name = "id-aes256-GCM" and result = "id-aes256-GCM"
228+
or
229+
name = "idea" and result = "IDEA-CBC"
230+
or
231+
name = "rc2" and result = "RC2-CBC"
232+
or
233+
name = "sm4" and result = "SM4-CBC"
234+
}
235+
236+
/**
237+
* Gets the canonical version of `name`, as reported by `OpenSSL::Cipher#name`.
238+
* No result if `name` is not a known OpenSSL cipher name.
239+
*/
240+
string getCanonicalCipherName(string name) {
241+
isOpenSSLCipher(name) and
242+
(
243+
if exists(string special | special = getSpecialCanonicalCipherName(name))
244+
then result = getSpecialCanonicalCipherName(name)
245+
else result = name.toUpperCase()
246+
)
247+
}
248+
249+
/**
250+
* Holds if `name` is the name of an OpenSSL cipher that is known to be weak.
251+
*/
110252
predicate isWeakOpenSSLCipher(string name) {
111253
isOpenSSLCipher(name) and
112254
name.toUpperCase().regexpMatch(getInsecureAlgorithmRegex())
113255
}
114256

257+
/**
258+
* Holds if `name` is the name of an OpenSSL cipher that is known to be strong.
259+
*/
115260
predicate isStrongOpenSSLCipher(string name) {
116261
isOpenSSLCipher(name) and
117262
name.toUpperCase().regexpMatch(getSecureAlgorithmRegex()) and
@@ -142,9 +287,19 @@ class OpenSSLCipher extends MkOpenSSLCipher {
142287

143288
OpenSSLCipher() { this = MkOpenSSLCipher(name, isWeak) }
144289

290+
/**
291+
* Gets a name of this cipher.
292+
*/
145293
string getName() { result = name }
146294

295+
/**
296+
* Gets a name of this cipher in canonical form.
297+
*/
298+
string getCanonicalName() { result = getCanonicalCipherName(this.getName()) }
299+
300+
/** Holds if this algorithm is weak. */
147301
predicate isWeak() { isWeak = true }
148302

149-
string toString() { result = this.getName() }
303+
/** Gets a textual representation of this element. */
304+
string toString() { result = this.getCanonicalName() }
150305
}

0 commit comments

Comments
 (0)