Skip to content

Commit 64cf27a

Browse files
committed
JS: Modernize crypto libraries
1 parent 40530ae commit 64cf27a

File tree

1 file changed

+59
-85
lines changed

1 file changed

+59
-85
lines changed

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

Lines changed: 59 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ private module BrowserIdCrypto {
149149
* A model of the Node.js builtin crypto library.
150150
*/
151151
private module NodeJSCrypto {
152-
private class InstantiatedAlgorithm extends DataFlow::CallNode {
152+
private class InstantiatedAlgorithm extends API::CallNode {
153153
private string algorithmName;
154154

155155
InstantiatedAlgorithm() {
@@ -166,11 +166,11 @@ private module NodeJSCrypto {
166166
* Also matches `createHash`, `createHmac`, `createSign` instead of `createCipher`.
167167
*/
168168

169-
exists(DataFlow::SourceNode mod |
170-
mod = DataFlow::moduleImport("crypto") and
171-
this = mod.getAMemberCall("create" + ["Hash", "Hmac", "Sign", "Cipher"]) and
172-
algorithmName = this.getArgument(0).getStringValue()
173-
)
169+
this =
170+
API::moduleImport("crypto")
171+
.getMember("create" + ["Hash", "Hmac", "Sign", "Cipher"])
172+
.getACall() and
173+
algorithmName = this.getArgument(0).getStringValue()
174174
}
175175

176176
CryptographicAlgorithm getAlgorithm() { result.matchesName(algorithmName) }
@@ -197,13 +197,12 @@ private module NodeJSCrypto {
197197
// crypto.generateKeyPair(type, options, callback)
198198
// crypto.generateKeyPairSync(type, options)
199199
// crypto.generateKeySync(type, options)
200-
exists(DataFlow::SourceNode mod, string keyType |
200+
exists(string keyType |
201201
keyType = "Key" and symmetric = true
202202
or
203203
keyType = "KeyPair" and symmetric = false
204204
|
205-
mod = DataFlow::moduleImport("crypto") and
206-
this = mod.getAMemberCall("generate" + keyType + ["", "Sync"])
205+
this = API::moduleImport("crypto").getMember("generate" + keyType + ["", "Sync"]).getACall()
207206
)
208207
}
209208

@@ -249,17 +248,15 @@ private module NodeJSCrypto {
249248

250249
private class Key extends CryptographicKey {
251250
Key() {
252-
exists(InstantiatedAlgorithm instantiation, string name |
253-
name = "setPrivateKey" or
254-
name = "sign"
255-
|
256-
this = instantiation.getAMethodCall(name).getArgument(0)
257-
)
251+
this =
252+
any(InstantiatedAlgorithm i)
253+
.getReturn()
254+
.getMember(["setPrivateKey", "sign"])
255+
.getParameter(0)
256+
.asSink()
258257
or
259-
exists(DataFlow::SourceNode mod, string name, DataFlow::InvokeNode call, int index |
260-
mod = DataFlow::moduleImport("crypto") and
261-
call = mod.getAMemberCall(name) and
262-
this = call.getArgument(index)
258+
exists(string name, int index |
259+
this = API::moduleImport("crypto").getMember(name).getACall().getArgument(index)
263260
|
264261
index = 0 and
265262
(name = "privateDecrypt" or name = "privateEncrypt")
@@ -497,13 +494,12 @@ private module TweetNaCl {
497494
* Also matches the "hash" method name, and the "nacl-fast" module.
498495
*/
499496

500-
exists(DataFlow::SourceNode mod, string name |
497+
exists(string name |
501498
name = "hash" and algorithm.matchesName("SHA512")
502499
or
503500
name = "sign" and algorithm.matchesName("ed25519")
504501
|
505-
(mod = DataFlow::moduleImport("nacl") or mod = DataFlow::moduleImport("nacl-fast")) and
506-
this = mod.getAMemberCall(name) and
502+
this = API::moduleImport(["nacl", "nacl-fast"]).getMember(name).getACall() and
507503
super.getArgument(0) = input
508504
)
509505
}
@@ -529,17 +525,13 @@ private module HashJs {
529525
*/
530526
private DataFlow::CallNode getAlgorithmNode(CryptographicAlgorithm algorithm) {
531527
exists(string algorithmName | algorithm.matchesName(algorithmName) |
532-
result = DataFlow::moduleMember("hash.js", algorithmName).getACall()
528+
result = API::moduleImport("hash.js").getMember(algorithmName).getACall()
533529
or
534-
exists(DataFlow::SourceNode mod |
535-
mod = DataFlow::moduleImport("hash.js/lib/hash/" + algorithmName)
536-
or
537-
exists(string size |
538-
mod = DataFlow::moduleImport("hash.js/lib/hash/sha/" + size) and
539-
algorithmName = "SHA" + size
540-
)
541-
|
542-
result = mod.getACall()
530+
result = API::moduleImport("hash.js/lib/hash/" + algorithmName).getACall()
531+
or
532+
exists(string size |
533+
result = API::moduleImport("hash.js/lib/hash/sha/" + size).getACall() and
534+
algorithmName = "SHA" + size
543535
)
544536
)
545537
}
@@ -579,10 +571,7 @@ private module HashJs {
579571
* A model of the forge library.
580572
*/
581573
private module Forge {
582-
private DataFlow::SourceNode getAnImportNode() {
583-
result = DataFlow::moduleImport("forge") or
584-
result = DataFlow::moduleImport("node-forge")
585-
}
574+
private API::Node getAnImportNode() { result = API::moduleImport(["forge", "node-forge"]) }
586575

587576
abstract private class Cipher extends DataFlow::CallNode {
588577
abstract CryptographicAlgorithm getAlgorithm();
@@ -594,14 +583,14 @@ private module Forge {
594583
private string blockModeString;
595584

596585
KeyCipher() {
597-
exists(DataFlow::SourceNode mod, string algorithmName |
598-
mod = getAnImportNode() and
599-
algorithm.matchesName(algorithmName)
600-
|
601-
exists(string createName, string cipherName, string cipherPrefix |
586+
exists(string algorithmName | algorithm.matchesName(algorithmName) |
587+
exists(string cipherName, string cipherPrefix |
602588
// `require('forge').cipher.createCipher("3DES-CBC").update("secret", "key");`
603-
(createName = "createCipher" or createName = "createDecipher") and
604-
this = mod.getAPropertyRead("cipher").getAMemberCall(createName) and
589+
this =
590+
getAnImportNode()
591+
.getMember("cipher")
592+
.getMember(["createCipher", "createDecipher"])
593+
.getACall() and
605594
this.getArgument(0).mayHaveStringValue(cipherName) and
606595
cipherName = cipherPrefix + "-" + blockModeString and
607596
blockModeString = ["CBC", "CFB", "CTR", "ECB", "GCM", "OFB"] and
@@ -610,13 +599,13 @@ private module Forge {
610599
)
611600
or
612601
// `require("forge").rc2.createEncryptionCipher("key").update("secret");`
613-
exists(string createName |
614-
createName = "createEncryptionCipher" or createName = "createDecryptionCipher"
615-
|
616-
this = mod.getAPropertyRead(algorithmName).getAMemberCall(createName) and
617-
key = this.getArgument(0) and
618-
blockModeString = algorithmName
619-
)
602+
this =
603+
getAnImportNode()
604+
.getMember(algorithmName)
605+
.getMember(["createEncryptionCipher", "createDecryptionCipher"])
606+
.getACall() and
607+
key = this.getArgument(0) and
608+
blockModeString = algorithmName
620609
)
621610
}
622611

@@ -637,10 +626,7 @@ private module Forge {
637626
exists(string algorithmName | algorithm.matchesName(algorithmName) |
638627
// require("forge").md.md5.create().update('The quick brown fox jumps over the lazy dog');
639628
this =
640-
getAnImportNode()
641-
.getAPropertyRead("md")
642-
.getAPropertyRead(algorithmName)
643-
.getAMemberCall("create")
629+
getAnImportNode().getMember("md").getMember(algorithmName).getMember("create").getACall()
644630
)
645631
}
646632

@@ -676,15 +662,17 @@ private module Forge {
676662
// var cipher = forge.rc2.createEncryptionCipher(key, 128);
677663
this =
678664
getAnImportNode()
679-
.getAPropertyRead(any(string s | algorithm.matchesName(s)))
680-
.getAMemberCall("createEncryptionCipher")
665+
.getMember(any(string s | algorithm.matchesName(s)))
666+
.getMember("createEncryptionCipher")
667+
.getACall()
681668
or
682669
// var key = forge.random.getBytesSync(16);
683670
// var cipher = forge.cipher.createCipher('AES-CBC', key);
684671
this =
685672
getAnImportNode()
686-
.getAPropertyRead("cipher")
687-
.getAMemberCall(["createCipher", "createDecipher"]) and
673+
.getMember("cipher")
674+
.getMember(["createCipher", "createDecipher"])
675+
.getACall() and
688676
algorithm.matchesName(this.getArgument(0).getStringValue())
689677
}
690678

@@ -713,12 +701,9 @@ private module Md5 {
713701

714702
Apply() {
715703
// `require("md5")("message");`
716-
exists(DataFlow::SourceNode mod |
717-
mod = DataFlow::moduleImport("md5") and
718-
algorithm.matchesName("MD5") and
719-
this = mod.getACall() and
720-
super.getArgument(0) = input
721-
)
704+
algorithm.matchesName("MD5") and
705+
this = API::moduleImport("md5").getACall() and
706+
super.getArgument(0) = input
722707
}
723708

724709
override DataFlow::Node getAnInput() { result = input }
@@ -740,21 +725,12 @@ private module Bcrypt {
740725

741726
Apply() {
742727
// `require("bcrypt").hash(password);` with minor naming variations
743-
exists(DataFlow::SourceNode mod, string moduleName, string methodName |
744-
algorithm.matchesName("BCRYPT") and
745-
(
746-
moduleName = "bcrypt" or
747-
moduleName = "bcryptjs" or
748-
moduleName = "bcrypt-nodejs"
749-
) and
750-
(
751-
methodName = "hash" or
752-
methodName = "hashSync"
753-
) and
754-
mod = DataFlow::moduleImport(moduleName) and
755-
this = mod.getAMemberCall(methodName) and
756-
super.getArgument(0) = input
757-
)
728+
algorithm.matchesName("BCRYPT") and
729+
this =
730+
API::moduleImport(["bcrypt", "bcryptjs", "bcrypt-nodejs"])
731+
.getMember(["hash", "hashSync"])
732+
.getACall() and
733+
super.getArgument(0) = input
758734
}
759735

760736
override DataFlow::Node getAnInput() { result = input }
@@ -776,13 +752,11 @@ private module Hasha {
776752

777753
Apply() {
778754
// `require('hasha')('unicorn', { algorithm: "md5" });`
779-
exists(DataFlow::SourceNode mod, string algorithmName, DataFlow::Node algorithmNameNode |
780-
mod = DataFlow::moduleImport("hasha") and
781-
this = mod.getACall() and
755+
exists(string algorithmName |
756+
this = API::moduleImport("hasha").getACall() and
782757
super.getArgument(0) = input and
783758
algorithm.matchesName(algorithmName) and
784-
super.getOptionArgument(1, "algorithm") = algorithmNameNode and
785-
algorithmNameNode.mayHaveStringValue(algorithmName)
759+
super.getOptionArgument(1, "algorithm").mayHaveStringValue(algorithmName)
786760
)
787761
}
788762

@@ -800,7 +774,7 @@ private module Hasha {
800774
*/
801775
private module ExpressJwt {
802776
private class Key extends CryptographicKey {
803-
Key() { this = DataFlow::moduleMember("express-jwt", "sign").getACall().getArgument(1) }
777+
Key() { this = API::moduleImport("express-jwt").getMember("sign").getACall().getArgument(1) }
804778
}
805779
}
806780

0 commit comments

Comments
 (0)