Skip to content

Commit 03c2dfa

Browse files
committed
Multiple bug fixes in BouncyCastle signature model
1 parent 03cea65 commit 03c2dfa

File tree

3 files changed

+56
-90
lines changed

3 files changed

+56
-90
lines changed
Lines changed: 24 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
1-
21
import java
32

43
/**
54
* Models for the signature algorithms defined by the `org.bouncycastle.crypto.signers` package.
6-
*
75
*/
86
module Signers {
97
import Language
108
import BouncyCastle.FlowAnalysis
119
import BouncyCastle.AlgorithmInstances
1210

13-
abstract class SignatureAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer { }
14-
1511
/**
1612
* A model of the `Signer` class in Bouncy Castle.
1713
*/
@@ -21,70 +17,49 @@ module Signers {
2117
this.getName().matches("%Signer")
2218
}
2319

24-
MethodCall getAnInitCall() {
25-
result = this.getAMethodCall("init")
26-
}
20+
MethodCall getAnInitCall() { result = this.getAMethodCall("init") }
2721

2822
MethodCall getAUseCall() {
2923
result = this.getAMethodCall(["update", "generateSignature", "verifySignature"])
3024
}
31-
25+
3226
MethodCall getAMethodCall(string name) {
3327
result.getCallee().hasQualifiedName("org.bouncycastle.crypto.signers", this.getName(), name)
3428
}
3529
}
3630

3731
/**
3832
* BouncyCastle algorithms are instantiated by calling the constructor of the
39-
* corresponding class. The algorithm is implicitly defined by the constructor
40-
* call.
33+
* corresponding class.
4134
*/
42-
class NewCall extends SignatureAlgorithmValueConsumer instanceof ClassInstanceExpr {
43-
NewCall() {
44-
this.getConstructedType() instanceof Signer
45-
}
46-
47-
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
48-
result = getSignatureAlgorithmInstanceFromType(super.getConstructedType())
49-
}
50-
51-
// TODO: Since the algorithm is implicitly defined by the constructor, should
52-
// the input node be `this`?
53-
override Crypto::ConsumerInputDataFlowNode getInputNode() {
54-
result.asExpr() = this
55-
}
56-
}
35+
class NewCall = SignatureAlgorithmInstance;
5736

5837
/**
5938
* The type is instantiated by a constructor call and initialized by a call to
6039
* `init()` which takes two arguments. The first argument is a flag indicating
6140
* whether the operation is signing data or verifying a signature, and the
62-
* second is the key to use.
41+
* second is the key to use.
6342
*/
6443
class InitCall extends MethodCall {
65-
InitCall() {
66-
this = any(Signer signer).getAnInitCall()
67-
}
44+
InitCall() { this = any(Signer signer).getAnInitCall() }
6845

6946
Expr getForSigningArg() { result = this.getArgument(0) }
7047

7148
Expr getKeyArg() { result = this.getArgument(1) }
7249

73-
Crypto::KeyOperationAlgorithmInstance getAlgorithm() {
74-
result = getSignatureAlgorithmInstanceFromType(this.getReceiverType())
75-
}
76-
50+
// TODO: Support dataflow for the operation sub-type.
7751
Crypto::KeyOperationSubtype getKeyOperationSubtype() {
78-
(
52+
if this.isOperationSubTypeKnown()
53+
then
7954
this.getForSigningArg().(BooleanLiteral).getBooleanValue() = true and
8055
result = Crypto::TSignMode()
81-
) or (
56+
or
8257
this.getForSigningArg().(BooleanLiteral).getBooleanValue() = false and
8358
result = Crypto::TVerifyMode()
84-
) or (
85-
result = Crypto::TUnknownKeyOperationMode()
86-
)
59+
else result = Crypto::TUnknownKeyOperationMode()
8760
}
61+
62+
predicate isOperationSubTypeKnown() { this.getForSigningArg() instanceof BooleanLiteral }
8863
}
8964

9065
/**
@@ -93,19 +68,13 @@ module Signers {
9368
* verify the signature, respectively.
9469
*/
9570
class UseCall extends MethodCall {
96-
UseCall() {
97-
this = any(Signer signer).getAUseCall()
98-
}
71+
UseCall() { this = any(Signer signer).getAUseCall() }
9972

100-
predicate isIntermediate() {
101-
this.getCallee().getName() = "update"
102-
}
73+
predicate isIntermediate() { this.getCallee().getName() = "update" }
10374

10475
Expr getInput() { result = this.getArgument(0) }
10576

106-
Expr getOutput() {
107-
result = this
108-
}
77+
Expr getOutput() { result = this }
10978
}
11079

11180
/**
@@ -118,10 +87,12 @@ module Signers {
11887
* or `verifySignature()` on a `Signer` instance.
11988
*/
12089
class SignatureOperationInstance extends Crypto::KeyOperationInstance instanceof UseCall {
121-
90+
SignatureOperationInstance() { not this.isIntermediate() }
91+
12292
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
123-
result = FlowAnalysis::getInstantiationFromInit(this.getInitCall(), _, _)
93+
result = FlowAnalysis::getInstantiationFromUse(this, _, _)
12494
}
95+
12596
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
12697
if FlowAnalysis::hasInit(this)
12798
then result = this.getInitCall().getKeyOperationSubtype()
@@ -144,17 +115,12 @@ module Signers {
144115
result.asExpr() = super.getOutput()
145116
}
146117

147-
InitCall getInitCall() {
148-
result = FlowAnalysis::getInitFromUse(this, _, _)
149-
}
118+
InitCall getInitCall() { result = FlowAnalysis::getInitFromUse(this, _, _) }
150119

151120
UseCall getAnUpdateCall() {
152-
(
153-
super.isIntermediate() and result = this
154-
) or (
155-
result = FlowAnalysis::getAnIntermediateUseFromFinalUse(this, _, _)
156-
)
121+
super.isIntermediate() and result = this
122+
or
123+
result = FlowAnalysis::getAnIntermediateUseFromFinalUse(this, _, _)
157124
}
158125
}
159126
}
160-
Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
11
import java
22
import experimental.quantum.Language
33
import AlgorithmInstances.SignatureAlgorithmInstances
4-
5-
SignatureAlgorithmInstance getSignatureAlgorithmInstanceFromType(Type t) {
6-
t.getName() = "Ed25519Signer" and result instanceof Ed25519AlgorithmInstance
7-
or
8-
t.getName() = "Ed448Signer" and result instanceof Ed448AlgorithmInstance
9-
}
10-
Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,51 @@
11
import java
22
import experimental.quantum.Language
33

4-
abstract class SignatureAlgorithmInstance extends Crypto::KeyOperationAlgorithmInstance {
4+
/**
5+
* Signature algorithms are implicitly defined by the constructor.
6+
*/
7+
private abstract class SignatureAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer {
8+
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
9+
result = this
10+
}
11+
12+
override Crypto::ConsumerInputDataFlowNode getInputNode() {
13+
none()
14+
}
15+
}
516

6-
// TODO: Could potentially be used to model signature modes like Ed25519ph and Ed25519ctx.
17+
class SignatureAlgorithmInstance extends Crypto::KeyOperationAlgorithmInstance, SignatureAlgorithmValueConsumer instanceof ClassInstanceExpr {
18+
SignatureAlgorithmInstance() {
19+
super.getConstructedType().getPackage().getName() = "org.bouncycastle.crypto.signers" and
20+
super.getConstructedType().getName().matches("%Signer")
21+
22+
}
23+
24+
// TODO: Could potentially be used to model signature modes like Ed25519ph and Ed25519ctx.
725
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() { none() }
826

927
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() { none() }
1028

1129
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() { none() }
12-
}
1330

14-
class Ed25519AlgorithmInstance extends SignatureAlgorithmInstance instanceof ClassInstanceExpr {
15-
Ed25519AlgorithmInstance() {
16-
this.getConstructedType().hasQualifiedName("org.bouncycastle.crypto.signers", "Ed25519Signer")
31+
override Crypto::KeyOpAlg::Algorithm getAlgorithmType() {
32+
nameToTypeAndKeySizeMapping(this.getRawAlgorithmName(), _, result)
1733
}
1834

19-
override string getRawAlgorithmName() { result = "Ed25519" }
20-
21-
override Crypto::KeyOpAlg::Algorithm getAlgorithmType() {
22-
result = Crypto::KeyOpAlg::TSignature(Crypto::KeyOpAlg::Ed25519())
23-
}
24-
25-
// TODO: May be redundant.
26-
override string getKeySizeFixed() { result = "256" }
27-
}
28-
29-
class Ed448AlgorithmInstance extends SignatureAlgorithmInstance instanceof ClassInstanceExpr {
30-
Ed448AlgorithmInstance() {
31-
this.getConstructedType().hasQualifiedName("org.bouncycastle.crypto.signers", "Ed448Signer")
35+
override string getRawAlgorithmName() {
36+
result = super.getConstructedType().getName().splitAt("Signer", 0)
3237
}
3338

34-
override string getRawAlgorithmName() { result = "Ed448" }
35-
36-
override Crypto::KeyOpAlg::Algorithm getAlgorithmType() {
37-
result = Crypto::KeyOpAlg::TSignature(Crypto::KeyOpAlg::Ed448())
39+
override string getKeySizeFixed() {
40+
nameToTypeAndKeySizeMapping(this.getRawAlgorithmName(), result, _)
3841
}
42+
}
3943

40-
// TODO: May be redundant.
41-
override string getKeySizeFixed() { result = "448" }
44+
predicate nameToTypeAndKeySizeMapping(string name, string keySize, Crypto::KeyOpAlg::Algorithm algorithm) {
45+
name = "Ed25519" and keySize = "256" and algorithm = Crypto::KeyOpAlg::TSignature(Crypto::KeyOpAlg::Ed25519())
46+
or
47+
name = "Ed448" and keySize = "448" and algorithm = Crypto::KeyOpAlg::TSignature(Crypto::KeyOpAlg::Ed448())
4248
}
4349

4450

51+

0 commit comments

Comments
 (0)