diff --git a/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptoArtifact.qll b/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptoArtifact.qll index 0aa91bff8c43..37266949c5ae 100644 --- a/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptoArtifact.qll +++ b/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptoArtifact.qll @@ -36,3 +36,9 @@ abstract class BlockMode extends CryptographicAlgorithm { else result = unknownAlgorithm() } } + +abstract class AsymmetricKeyCreation extends CryptographicArtifact { + abstract string getAlgorithmName(); + + abstract int getKeySize(); +} diff --git a/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptographyModule.qll b/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptographyModule.qll index 0e6b2a434733..bd3362dadcdb 100644 --- a/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptographyModule.qll +++ b/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptographyModule.qll @@ -194,3 +194,45 @@ class CipherBlockModeEnum extends BlockMode { override string getName() { result = modeName } } + +class RsaCreateKeyCreation extends AsymmetricKeyCreation, DataFlow::CallNode { + int keySize; + + RsaCreateKeyCreation() { + exists(string method | + method = ["create", "new"] and + this = + API::getTopLevelMember("system") + .getMember("security") + .getMember("cryptography") + .getMember(["rsa", "rsacryptoserviceprovider"]) + .getMember(method) + .asCall() + ) and + keySize = this.getAnArgument().asExpr().getExpr().(ConstExpr).getValueString().toInt() + } + + override string getAlgorithmName() { result = "rsa" } + + override int getKeySize() { result = keySize } +} + +class RsaCspObjectKeyCreation extends AsymmetricKeyCreation, CryptoAlgorithmObjectCreation { + int keySize; + + RsaCspObjectKeyCreation() { + objectName = + [ + "system.security.cryptography.rsacryptoserviceprovider", + "rsacryptoserviceprovider" + ] and + exists(DataFlow::Node arg | + arg = this.getAnArgument() and + keySize = arg.asExpr().getExpr().(ConstExpr).getValueString().toInt() + ) + } + + override string getAlgorithmName() { result = "rsa" } + + override int getKeySize() { result = keySize } +} diff --git a/powershell/ql/src/queries/security/cwe-327/WeakAsymmetricKeySize.qhelp b/powershell/ql/src/queries/security/cwe-327/WeakAsymmetricKeySize.qhelp new file mode 100644 index 000000000000..c7b5aa54f19e --- /dev/null +++ b/powershell/ql/src/queries/security/cwe-327/WeakAsymmetricKeySize.qhelp @@ -0,0 +1,32 @@ + + + +

+ Modern encryption relies on it being computationally infeasible to break the cipher and + decode a message without the key. As computational power increases, the ability to break + ciphers grows and keys need to become larger. +

+

+ RSA keys smaller than 2048 bits are considered weak and can potentially be broken using + modern hardware. Using such keys compromises the confidentiality and integrity of + encrypted data. +

+
+ + +

+ Use an RSA key size of at least 2048 bits. For long-term security, consider using + 4096-bit keys. +

+

+ When calling [System.Security.Cryptography.RSA]::Create() or creating an + RSACryptoServiceProvider, always specify a key size of 2048 or greater. +

+
+ + +
  • NIST, SP 800-131A: Transitioning the Use of Cryptographic Algorithms and Key Lengths.
  • +
  • Wikipedia: RSA cryptosystem.
  • +
  • CWE-327: Use of a Broken or Risky Cryptographic Algorithm.
  • +
    +
    diff --git a/powershell/ql/src/queries/security/cwe-327/WeakAsymmetricKeySize.ql b/powershell/ql/src/queries/security/cwe-327/WeakAsymmetricKeySize.ql new file mode 100644 index 000000000000..0e40edfb6b56 --- /dev/null +++ b/powershell/ql/src/queries/security/cwe-327/WeakAsymmetricKeySize.ql @@ -0,0 +1,22 @@ +/** + * @name Weak asymmetric key size + * @description Using RSA keys smaller than 2048 bits does not provide adequate security. + * @kind problem + * @problem.severity error + * @security-severity 7.5 + * @precision high + * @id powershell/weak-asymmetric-key-size + * @tags security + * external/cwe/cwe-327 + */ + +import powershell +import semmle.code.powershell.dataflow.DataFlow +import semmle.code.powershell.security.cryptography.Concepts + +from AsymmetricKeyCreation keyCreation, int keySize +where + keySize = keyCreation.getKeySize() and + keySize < 2048 +select keyCreation, + "RSA key size " + keySize.toString() + " bits is below the minimum of 2048 bits." diff --git a/powershell/ql/test/query-tests/security/cwe-327/WeakAsymmetricKeySize/WeakAsymmetricKeySize.expected b/powershell/ql/test/query-tests/security/cwe-327/WeakAsymmetricKeySize/WeakAsymmetricKeySize.expected new file mode 100644 index 000000000000..52e8dddddc7f --- /dev/null +++ b/powershell/ql/test/query-tests/security/cwe-327/WeakAsymmetricKeySize/WeakAsymmetricKeySize.expected @@ -0,0 +1,3 @@ +| test.ps1:6:8:6:55 | Call to create | RSA key size 1024 bits is below the minimum of 2048 bits. | +| test.ps1:9:8:9:54 | Call to create | RSA key size 512 bits is below the minimum of 2048 bits. | +| test.ps1:12:8:12:73 | Call to new | RSA key size 1024 bits is below the minimum of 2048 bits. | diff --git a/powershell/ql/test/query-tests/security/cwe-327/WeakAsymmetricKeySize/WeakAsymmetricKeySize.qlref b/powershell/ql/test/query-tests/security/cwe-327/WeakAsymmetricKeySize/WeakAsymmetricKeySize.qlref new file mode 100644 index 000000000000..67e632a55e00 --- /dev/null +++ b/powershell/ql/test/query-tests/security/cwe-327/WeakAsymmetricKeySize/WeakAsymmetricKeySize.qlref @@ -0,0 +1 @@ +queries/security/cwe-327/WeakAsymmetricKeySize.ql diff --git a/powershell/ql/test/query-tests/security/cwe-327/WeakAsymmetricKeySize/test.ps1 b/powershell/ql/test/query-tests/security/cwe-327/WeakAsymmetricKeySize/test.ps1 new file mode 100644 index 000000000000..12fd3c84331f --- /dev/null +++ b/powershell/ql/test/query-tests/security/cwe-327/WeakAsymmetricKeySize/test.ps1 @@ -0,0 +1,25 @@ +# =================================================================== +# ========== TRUE POSITIVES (should trigger alert) ================== +# =================================================================== + +# --- Case 1: RSA.Create with 1024-bit key --- +$rsa = [System.Security.Cryptography.RSA]::Create(1024) # BAD + +# --- Case 2: RSA.Create with 512-bit key --- +$rsa = [System.Security.Cryptography.RSA]::Create(512) # BAD + +# --- Case 3: RSACryptoServiceProvider with 1024-bit key via ::new() --- +$rsa = [System.Security.Cryptography.RSACryptoServiceProvider]::new(1024) # BAD + +# =================================================================== +# ========== TRUE NEGATIVES (should NOT trigger alert) ============== +# =================================================================== + +# --- Safe: RSA.Create with 2048-bit key --- +$rsa = [System.Security.Cryptography.RSA]::Create(2048) # GOOD + +# --- Safe: RSA.Create with 4096-bit key --- +$rsa = [System.Security.Cryptography.RSA]::Create(4096) # GOOD + +# --- Safe: RSA.Create with no argument (default key size) --- +$rsa = [System.Security.Cryptography.RSA]::Create() # GOOD