1+ /**
2+ * Provides classes modeling parts of the Ruby `OpenSSL` library, which wraps
3+ * the OpenSSL C library.
4+ */
5+
16private import CryptoAlgorithms:: AlgorithmNames
27
38bindingset [ 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