Python: Add concepts for public-key generation

I did spend some time to figure out how to best write `minimumSecureKeySize`
predicate. I wanted to write once and for all the recommended sizes for each
cryptosystem.

I considered making the predicate such as

```codeql
int minimumSecureKeySize() {
    this.getName() = "RSA" and result = 2048
    or
    this.getName() = "DSA" and result = 2048
    or
    this.getName() = "ECC" and result = 244
}
```

but then it would be impossible to add a new model without also being able to
modify the body of this predicate -- which seems like a bad way to start off a
brand new way of modeling things.

So I considered if we could add it to the non-range class, such as

```codeql
class RSAKeyGeneration extends KeyGeneration {
  RSAKeyGeneration() { this.getName() = "RSA" }

  override int minimumSecureKeySize() { result = 2048 }
}
```

This has the major problem that when you're writing the models for a new
API (and therefore extending KeyGeneration::Range), there is no way for you to
see that you need to take this extra step :| (also problem about how we should
define `minimumSecureKeySize` on `KeyGeneration` class then, since if we make it
abstract, we effectively disable the ability to refine `KeyGeneration` since any
subclass must provide an implementation.)

So, therefore I ended up with this solution ;)
This commit is contained in:
Rasmus Wriedt Larsen
2021-02-02 16:20:04 +01:00
parent 4ab61bb088
commit 11cd0dbbc0
2 changed files with 109 additions and 0 deletions

View File

@@ -526,3 +526,90 @@ module HTTP {
}
}
}
/** Provides models for cryptographic things. */
module Cryptography {
/** Provides models for public-key cryptography, also called asymmetric cryptography. */
module PublicKey {
/**
* A data-flow node that generates a new key-pair for use with public-key cryptography.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `KeyGeneration::Range` instead.
*/
class KeyGeneration extends DataFlow::Node {
KeyGeneration::Range range;
KeyGeneration() { this = range }
/** Gets the name of the cryptographic algorithm (for example `"RSA"` or `"AES"`). */
string getName() { result = range.getName() }
/** Gets the argument that specifies size of the key in bits, if available. */
DataFlow::Node getKeySizeArg() { result = range.getKeySizeArg() }
/**
* Gets the size of the key generated (in bits), as well as the `origin` that
* explains how we obtained this specific key size.
*/
int getKeySizeWithOrigin(DataFlow::Node origin) {
result = range.getKeySizeWithOrigin(origin)
}
/** Gets the minimum key size (in bits) for this algorithm to be considered secure. */
int minimumSecureKeySize() { result = range.minimumSecureKeySize() }
}
/** Provides classes for modeling new key-pair generation APIs. */
module KeyGeneration {
/**
* A data-flow node that generates a new key-pair for use with public-key cryptography.
*
* Extend this class to model new APIs. If you want to refine existing API models,
* extend `KeyGeneration` instead.
*/
abstract class Range extends DataFlow::Node {
/** Gets the name of the cryptographic algorithm (for example `"RSA"`). */
abstract string getName();
/** Gets the argument that specifies size of the key in bits, if available. */
abstract DataFlow::Node getKeySizeArg();
/**
* Gets the size of the key generated (in bits), as well as the `origin` that
* explains how we obtained this specific key size.
*/
int getKeySizeWithOrigin(DataFlow::Node origin) {
exists(IntegerLiteral size | origin = DataFlow::exprNode(size) |
origin.(DataFlow::LocalSourceNode).flowsTo(this.getKeySizeArg()) and
result = size.getValue()
)
}
/** Gets the minimum key size (in bits) for this algorithm to be considered secure. */
abstract int minimumSecureKeySize();
}
/** A data-flow node that generates a new RSA key-pair. */
abstract class RSARange extends Range {
override string getName() { result = "RSA" }
override int minimumSecureKeySize() { result = 2048 }
}
/** A data-flow node that generates a new DSA key-pair. */
abstract class DSARange extends Range {
override string getName() { result = "DSA" }
override int minimumSecureKeySize() { result = 2048 }
}
/** A data-flow node that generates a new ECC key-pair. */
abstract class ECCRange extends Range {
override string getName() { result = "ECC" }
override int minimumSecureKeySize() { result = 224 }
}
}
}
}