Skip to content

Commit 0cd3df9

Browse files
committed
Concepts for elliptic cureve and misc. updates.
1 parent e027b0e commit 0cd3df9

File tree

5 files changed

+392
-12
lines changed

5 files changed

+392
-12
lines changed

cpp/ql/lib/experimental/Quantum/Base.qll

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
9292
*/
9393
abstract string getAlgorithmName();
9494

95+
/**
96+
* Gets the raw name of this algorithm from source (no parsing or formatting)
97+
*/
98+
abstract string getRawAlgorithmName();
99+
95100
final override string toString() { result = this.getAlgorithmName() }
96101
}
97102

@@ -145,10 +150,6 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
145150

146151
override string getAlgorithmName() { this.hashTypeToNameMapping(this.getHashType(), result) }
147152

148-
/**
149-
* Gets the raw name of this hash algorithm from source.
150-
*/
151-
abstract string getRawAlgorithmName();
152153
}
153154

154155
/**
@@ -195,30 +196,55 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
195196
}
196197
}
197198

199+
newtype TEllipticCurveFamilyType =
200+
// We're saying by this that all of these have an identical interface / properties / edges
201+
NIST() or
202+
SEC() or
203+
NUMS() or
204+
PRIME() or
205+
BRAINPOOL() or
206+
CURVE25519() or
207+
CURVE448() or
208+
C2() or
209+
SM2() or
210+
ES() or
211+
OtherEllipticCurveFamilyType()
212+
213+
198214
/**
199215
* Elliptic curve algorithm
200216
*/
201217
abstract class EllipticCurve extends Algorithm {
202-
abstract string getVersion(Location location);
218+
203219

204220
abstract string getKeySize(Location location);
205221

222+
abstract TEllipticCurveFamilyType getCurveFamilyType();
223+
206224
override predicate properties(string key, string value, Location location) {
207225
super.properties(key, value, location)
208226
or
209-
key = "version" and
210-
if exists(this.getVersion(location))
211-
then value = this.getVersion(location)
212-
else (
213-
value instanceof UnknownPropertyValue and location instanceof UnknownLocation
214-
)
215-
or
216227
key = "key_size" and
217228
if exists(this.getKeySize(location))
218229
then value = this.getKeySize(location)
219230
else (
220231
value instanceof UnknownPropertyValue and location instanceof UnknownLocation
221232
)
233+
// other properties, like field type are possible, but not modeled until considered necessary
222234
}
235+
236+
override string getAlgorithmName() { result = this.getRawAlgorithmName().toUpperCase()}
237+
238+
/**
239+
* Mandating that for Elliptic Curves specifically, users are responsible
240+
* for providing as the 'raw' name, the official name of the algorithm.
241+
* Casing doesn't matter, we will enforce further naming restrictions on
242+
* `getAlgorithmName` by default.
243+
* Rationale: elliptic curve names can have a lot of variation in their components
244+
* (e.g., "secp256r1" vs "P-256"), trying to produce generalized set of properties
245+
* is possible to capture all cases, but such modeling is likely not necessary.
246+
* if all properties need to be captured, we can reassess how names are generated.
247+
*/
248+
override abstract string getRawAlgorithmName();
223249
}
224250
}
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
/**
2+
* A language-independent library for reasoning about cryptography.
3+
*/
4+
5+
import codeql.util.Location
6+
import codeql.util.Option
7+
8+
signature module InputSig<LocationSig Location> {
9+
class LocatableElement {
10+
Location getLocation();
11+
}
12+
13+
class UnknownLocation instanceof Location;
14+
}
15+
16+
module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
17+
final class LocatableElement = Input::LocatableElement;
18+
19+
final class UnknownLocation = Input::UnknownLocation;
20+
21+
final class UnknownPropertyValue extends string {
22+
UnknownPropertyValue() { this = "<unknown>" }
23+
}
24+
25+
abstract class NodeBase instanceof LocatableElement {
26+
/**
27+
* Returns a string representation of this node, usually the name of the operation/algorithm/property.
28+
*/
29+
abstract string toString();
30+
31+
/**
32+
* Returns the location of this node in the code.
33+
*/
34+
Location getLocation() { result = super.getLocation() }
35+
36+
/**
37+
* Gets the origin of this node, e.g., a string literal in source describing it.
38+
*/
39+
LocatableElement getOrigin(string value) { none() }
40+
41+
/**
42+
* Returns the child of this node with the given edge name.
43+
*
44+
* This predicate is used by derived classes to construct the graph of cryptographic operations.
45+
*/
46+
NodeBase getChild(string edgeName) { none() }
47+
48+
/**
49+
* Defines properties of this node by name and either a value or location or both.
50+
*
51+
* This predicate is used by derived classes to construct the graph of cryptographic operations.
52+
*/
53+
predicate properties(string key, string value, Location location) {
54+
key = "origin" and location = this.getOrigin(value).getLocation()
55+
}
56+
57+
/**
58+
* Returns the parent of this node.
59+
*/
60+
final NodeBase getAParent() { result.getChild(_) = this }
61+
}
62+
63+
class Asset = NodeBase;
64+
65+
/**
66+
* A cryptographic operation, such as hashing or encryption.
67+
*/
68+
abstract class Operation extends Asset {
69+
/**
70+
* Gets the algorithm associated with this operation.
71+
*/
72+
abstract Algorithm getAlgorithm();
73+
74+
/**
75+
* Gets the name of this operation, e.g., "hash" or "encrypt".
76+
*/
77+
abstract string getOperationName();
78+
79+
final override string toString() { result = this.getOperationName() }
80+
81+
override NodeBase getChild(string edgeName) {
82+
result = super.getChild(edgeName)
83+
or
84+
edgeName = "uses" and
85+
if exists(this.getAlgorithm()) then result = this.getAlgorithm() else result = this
86+
}
87+
}
88+
89+
abstract class Algorithm extends Asset {
90+
/**
91+
* Gets the name of this algorithm, e.g., "AES" or "SHA".
92+
*/
93+
abstract string getAlgorithmName();
94+
95+
/**
96+
* Gets the raw name of this algorithm from source (no parsing or formatting)
97+
*/
98+
abstract string getRawAlgorithmName();
99+
100+
final override string toString() { result = this.getAlgorithmName() }
101+
}
102+
103+
/**
104+
* A hashing operation that processes data to generate a hash value.
105+
* This operation takes an input message of arbitrary content and length and produces a fixed-size
106+
* hash value as the output using a specified hashing algorithm.
107+
*/
108+
abstract class HashOperation extends Operation {
109+
abstract override HashAlgorithm getAlgorithm();
110+
111+
override string getOperationName() { result = "HASH" }
112+
}
113+
114+
// Rule: no newtype representing a type of algorithm should be modelled with multiple interfaces
115+
//
116+
// Example: HKDF and PKCS12KDF are both key derivation algorithms.
117+
// However, PKCS12KDF also has a property: the iteration count.
118+
//
119+
// If we have HKDF and PKCS12KDF under TKeyDerivationType,
120+
// someone modelling a library might try to make a generic identification of both of those algorithms.
121+
//
122+
// They will therefore not use the specialized type for PKCS12KDF,
123+
// meaning "from PKCS12KDF algo select algo" will have no results.
124+
//
125+
newtype THashType =
126+
// We're saying by this that all of these have an identical interface / properties / edges
127+
MD5() or
128+
SHA1() or
129+
SHA256() or
130+
SHA512() or
131+
OtherHashType()
132+
133+
/**
134+
* A hashing algorithm that transforms variable-length input into a fixed-size hash value.
135+
*/
136+
abstract class HashAlgorithm extends Algorithm {
137+
final predicate hashTypeToNameMapping(THashType type, string name) {
138+
type instanceof MD5 and name = "MD5"
139+
or
140+
type instanceof SHA1 and name = "SHA-1"
141+
or
142+
type instanceof SHA256 and name = "SHA-256"
143+
or
144+
type instanceof SHA512 and name = "SHA-512"
145+
or
146+
type instanceof OtherHashType and name = this.getRawAlgorithmName()
147+
}
148+
149+
abstract THashType getHashType();
150+
151+
override string getAlgorithmName() { this.hashTypeToNameMapping(this.getHashType(), result) }
152+
153+
}
154+
155+
/**
156+
* An operation that derives one or more keys from an input value.
157+
*/
158+
abstract class KeyDerivationOperation extends Operation {
159+
override string getOperationName() { result = "KEY_DERIVATION" }
160+
}
161+
162+
/**
163+
* An algorithm that derives one or more keys from an input value.
164+
*/
165+
abstract class KeyDerivationAlgorithm extends Algorithm {
166+
abstract override string getAlgorithmName();
167+
}
168+
169+
/**
170+
* HKDF key derivation function
171+
*/
172+
abstract class HKDF extends KeyDerivationAlgorithm {
173+
final override string getAlgorithmName() { result = "HKDF" }
174+
175+
abstract HashAlgorithm getHashAlgorithm();
176+
177+
override NodeBase getChild(string edgeName) {
178+
result = super.getChild(edgeName)
179+
or
180+
edgeName = "digest" and result = this.getHashAlgorithm()
181+
}
182+
}
183+
184+
/**
185+
* PKCS #12 key derivation function
186+
*/
187+
abstract class PKCS12KDF extends KeyDerivationAlgorithm {
188+
final override string getAlgorithmName() { result = "PKCS12KDF" }
189+
190+
abstract HashAlgorithm getHashAlgorithm();
191+
192+
override NodeBase getChild(string edgeName) {
193+
result = super.getChild(edgeName)
194+
or
195+
edgeName = "digest" and result = this.getHashAlgorithm()
196+
}
197+
}
198+
199+
newtype TEllipticCurveFamilyType =
200+
// We're saying by this that all of these have an identical interface / properties / edges
201+
NIST() or
202+
SEC() or
203+
NUMS() or
204+
PRIME() or
205+
BRAINPOOL() or
206+
CURVE25519() or
207+
CURVE448() or
208+
C2() or
209+
SM2() or
210+
ES() or
211+
OtherEllipticCurveFamilyType()
212+
213+
214+
/**
215+
* Elliptic curve algorithm
216+
*/
217+
abstract class EllipticCurve extends Algorithm {
218+
219+
220+
abstract string getKeySize(Location location);
221+
222+
abstract TEllipticCurveFamilyType getCurveFamilyType();
223+
224+
override predicate properties(string key, string value, Location location) {
225+
super.properties(key, value, location)
226+
or
227+
key = "key_size" and
228+
if exists(this.getKeySize(location))
229+
then value = this.getKeySize(location)
230+
else (
231+
value instanceof UnknownPropertyValue and location instanceof UnknownLocation
232+
)
233+
// other properties, like field type are possible, but not modeled until considered necessary
234+
}
235+
236+
override string getAlgorithmName() { result = this.getRawAlgorithmName().toUpperCase()}
237+
238+
/**
239+
* Mandating that for Elliptic Curves specifically, users are responsible
240+
* for providing as the 'raw' name, the official name of the algorithm.
241+
* Casing doesn't matter, we will enforce further naming restrictions on
242+
* `getAlgorithmName` by default.
243+
* Rationale: elliptic curve names can have a lot of variation in their components
244+
* (e.g., "secp256r1" vs "P-256"), trying to produce generalized set of properties
245+
* is possible to capture all cases, but such modeling is likely not necessary.
246+
* if all properties need to be captured, we can reassess how names are generated.
247+
*/
248+
override abstract string getRawAlgorithmName();
249+
}
250+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
private import Base
2+
private import python as Lang
3+
4+
module CryptoInput implements InputSig<Lang::Location> {
5+
class LocatableElement = Lang::Expr;
6+
7+
class UnknownLocation = Lang::UnknownDefaultLocation;
8+
}
9+
10+
module Crypto = CryptographyBase<Lang::Location, CryptoInput>;
11+
12+
import PycaCryptography

0 commit comments

Comments
 (0)