Skip to content

Commit fa10710

Browse files
committed
add initial work for openssl signatures
1 parent 105ca2e commit fa10710

3 files changed

Lines changed: 194 additions & 0 deletions

File tree

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import cpp
2+
private import experimental.quantum.Language
3+
private import KnownAlgorithmConstants
4+
private import Crypto::KeyOpAlg as KeyOpAlg
5+
private import OpenSSLAlgorithmInstanceBase
6+
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
7+
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
8+
private import AlgToAVCFlow
9+
10+
11+
/**
12+
* Gets the signature algorithm type based on the normalized algorithm name.
13+
*/
14+
private predicate knownOpenSSLConstantToSignatureFamilyType(
15+
KnownOpenSSLSignatureAlgorithmConstant e, Crypto::KeyOpAlg::TAlgorithm type
16+
) {
17+
exists(string name |
18+
name = e.getNormalizedName() and
19+
(
20+
name.matches("rsa%") and type = KeyOpAlg::TAsymmetricCipher(KeyOpAlg::RSA())
21+
or
22+
name.matches("dsa%") and type = KeyOpAlg::TSignature(KeyOpAlg::DSA())
23+
or
24+
name.matches("ecdsa%") and type = KeyOpAlg::TSignature(KeyOpAlg::ECDSA())
25+
or
26+
name.matches("ed25519%") and type = KeyOpAlg::TSignature(KeyOpAlg::Ed25519())
27+
or
28+
name.matches("ed448%") and type = KeyOpAlg::TSignature(KeyOpAlg::Ed448())
29+
// or
30+
// name.matches("sm2%") and type = KeyOpAlg::TSignature(KeyOpAlg::SM2())
31+
// or
32+
// name.matches("ml-dsa%") and type = KeyOpAlg::TSignature(KeyOpAlg::MLDSA())
33+
// or
34+
// name.matches("slh-dsa%") and type = KeyOpAlg::TSignature(KeyOpAlg::SLHDSA())
35+
)
36+
)
37+
}
38+
39+
/**
40+
* A signature algorithm instance derived from an OpenSSL constant.
41+
*/
42+
class KnownOpenSSLSignatureConstantAlgorithmInstance extends OpenSSLAlgorithmInstance,
43+
Crypto::KeyOperationAlgorithmInstance instanceof KnownOpenSSLSignatureAlgorithmConstant
44+
{
45+
OpenSSLAlgorithmValueConsumer getterCall;
46+
47+
KnownOpenSSLSignatureConstantAlgorithmInstance() {
48+
// Two possibilities:
49+
// 1) The source is a literal and flows to a getter, then we know we have an instance
50+
// 2) The source is a KnownOpenSSLAlgorithm call, and we know we have an instance immediately from that
51+
52+
// Possibility 1:
53+
this instanceof Literal and
54+
exists(DataFlow::Node src, DataFlow::Node sink |
55+
// Sink is an argument to a signature getter call
56+
sink = getterCall.getInputNode() and
57+
// Source is `this`
58+
src.asExpr() = this and
59+
// This traces to a getter
60+
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
61+
)
62+
or
63+
// Possibility 2:
64+
this instanceof DirectAlgorithmValueConsumer and getterCall = this
65+
}
66+
67+
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() {
68+
none()
69+
}
70+
71+
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() {
72+
none()
73+
}
74+
75+
override string getRawAlgorithmName() { result = this.(Literal).getValue().toString() }
76+
77+
override int getKeySizeFixed() {
78+
// this.(KnownOpenSSLSignatureAlgorithmConstant).getExplicitKeySize() = result
79+
none()
80+
}
81+
82+
override KeyOpAlg::Algorithm getAlgorithmType() {
83+
knownOpenSSLConstantToSignatureFamilyType(this, result)
84+
or
85+
not knownOpenSSLConstantToSignatureFamilyType(this, _) and
86+
result = KeyOpAlg::TSignature(KeyOpAlg::OtherSignatureAlgorithmType())
87+
}
88+
89+
override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall }
90+
91+
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
92+
// TODO: trace to any key size initializer, symmetric and asymmetric
93+
none()
94+
}
95+
96+
override predicate shouldHaveModeOfOperation() {
97+
none()
98+
}
99+
100+
override predicate shouldHavePaddingScheme() {
101+
none()
102+
}
103+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import cpp
2+
private import experimental.quantum.Language
3+
private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
4+
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
5+
private import OpenSSLAlgorithmValueConsumerBase
6+
7+
abstract class SignatureAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer { }
8+
9+
class EVPSignatureAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer {
10+
DataFlow::Node valueArgNode;
11+
DataFlow::Node resultNode;
12+
Function consumer;
13+
14+
EVPSignatureAlgorithmValueConsumer() {
15+
resultNode.asExpr() = this and
16+
this.(Call).getTarget() = consumer and
17+
(
18+
// EVP_SIGNATURE
19+
consumer.getName() = "EVP_SIGNATURE_fetch" and
20+
valueArgNode.asExpr() = this.(Call).getArgument(1)
21+
or
22+
consumer.getName() = "EVP_SIGNATURE_is_a" and
23+
valueArgNode.asExpr() = this.(Call).getArgument(1)
24+
// EVP_PKEY_get1_DSA, DSA_SIG_new, EVP_RSA_gen
25+
)
26+
}
27+
28+
override DataFlow::Node getResultNode() { result = resultNode }
29+
30+
override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode }
31+
32+
// override DataFlow::Node getInputNode() { result = valueArgNode }
33+
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
34+
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i)
35+
//TODO: As a potential alternative, for OpenSSL only, add a generic source node for literals and only create flow (flowsTo) to
36+
// OpenSSL AVCs... the unknown literal sources would have to be any literals not in the known set.
37+
}
38+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* Provides classes for modeling OpenSSL's EVP signature operations
3+
*/
4+
5+
private import experimental.quantum.Language
6+
private import OpenSSLOperationBase
7+
private import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
8+
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
9+
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
10+
11+
// TODO: verification
12+
13+
abstract class EVP_Cipher_Initializer extends EVPInitialize {
14+
Expr keyArg;
15+
Expr algorithmArg;
16+
17+
EVP_Cipher_Initializer() {
18+
this.(Call).getTarget().getName() in [
19+
"EVP_DigestSignInit", "EVP_DigestSignInit_ex",
20+
"EVP_SignInit", "EVP_SignInit_ex",
21+
"EVP_PKEY_sign_init", "EVP_PKEY_sign_init_ex", "EVP_PKEY_sign_init_ex2", "EVP_PKEY_sign_message_init"
22+
] and
23+
(
24+
this.(Call).getTarget().getName() = "EVP_DigestSignInit" and
25+
keyArg = this.(Call).getArgument(5)
26+
or
27+
this.(Call).getTarget().getName() = "EVP_DigestSignInit_ex" and
28+
keyArg = this.(Call).getArgument(4)
29+
or
30+
this.(Call).getTarget().getName() = "EVP_PKEY_sign_init_ex2" and
31+
algorithmArg = this.(Call).getArgument(1)
32+
or
33+
this.(Call).getTarget().getName() = "EVP_PKEY_sign_message_init" and
34+
algorithmArg = this.(Call).getArgument(1)
35+
)
36+
}
37+
38+
override Expr getAlgorithmArg() { result = algorithmArg }
39+
40+
override Expr getKeyArg() { result = keyArg }
41+
42+
override Expr getIVArg() { none() }
43+
44+
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
45+
if this.(Call).getTarget().getName().toLowerCase().matches("%sign%")
46+
then result instanceof Crypto::TSignMode
47+
else
48+
if this.(Call).getTarget().getName().toLowerCase().matches("%verify%")
49+
then result instanceof Crypto::TVerifyMode
50+
else
51+
result instanceof Crypto::TUnknownKeyOperationMode
52+
}
53+
}

0 commit comments

Comments
 (0)