mirror of
https://github.com/github/codeql.git
synced 2025-12-18 01:33:15 +01:00
Crypto: Add modeling for JCA signatures. Make consistent use of "unknown" or "other" for unrecognized types.
This commit is contained in:
@@ -18,6 +18,8 @@ module JCAModel {
|
|||||||
|
|
||||||
abstract class KeyAgreementAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer { }
|
abstract class KeyAgreementAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer { }
|
||||||
|
|
||||||
|
abstract class SignatureAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer { }
|
||||||
|
|
||||||
// TODO: Verify that the PBEWith% case works correctly
|
// TODO: Verify that the PBEWith% case works correctly
|
||||||
bindingset[algo]
|
bindingset[algo]
|
||||||
predicate cipher_names(string algo) {
|
predicate cipher_names(string algo) {
|
||||||
@@ -100,6 +102,12 @@ module JCAModel {
|
|||||||
].toUpperCase())
|
].toUpperCase())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindingset[name]
|
||||||
|
predicate signature_names(string name) {
|
||||||
|
name.toUpperCase().splitAt("with".toUpperCase(), 1).matches(["RSA", "ECDSA", "DSA"])
|
||||||
|
// note RSASSA-PSS is RSA with PSS where the digest is set through PSSParameterSpec
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[name]
|
bindingset[name]
|
||||||
predicate key_agreement_names(string name) {
|
predicate key_agreement_names(string name) {
|
||||||
name.toUpperCase().matches(["DH", "EDH", "ECDH", "X25519", "X448"].toUpperCase())
|
name.toUpperCase().matches(["DH", "EDH", "ECDH", "X25519", "X448"].toUpperCase())
|
||||||
@@ -217,6 +225,25 @@ module JCAModel {
|
|||||||
name.toUpperCase() in ["ECDH", "X25519", "X448"]
|
name.toUpperCase() in ["ECDH", "X25519", "X448"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindingset[name]
|
||||||
|
predicate signature_name_to_type_known(Crypto::KeyOpAlg::TAlgorithm type, string name) {
|
||||||
|
name.toUpperCase().splitAt("with".toUpperCase(), 1) = "RSA" and
|
||||||
|
type = KeyOpAlg::TAsymmetricCipher(KeyOpAlg::RSA())
|
||||||
|
or
|
||||||
|
name.toUpperCase().splitAt("with".toUpperCase(), 1) = "ECDSA" and
|
||||||
|
type = KeyOpAlg::TSignature(KeyOpAlg::ECDSA())
|
||||||
|
or
|
||||||
|
name.toUpperCase().splitAt("with".toUpperCase(), 1) = "DSA" and
|
||||||
|
type = KeyOpAlg::TSignature(KeyOpAlg::DSA())
|
||||||
|
or
|
||||||
|
name.toUpperCase().matches("RSASSA-PSS") and type = KeyOpAlg::TAsymmetricCipher(KeyOpAlg::RSA())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[name]
|
||||||
|
Crypto::HashType signature_name_to_hash_type_known(string name, int digestLength) {
|
||||||
|
result = hash_name_to_type_known(name.splitAt("with", 0), digestLength)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `StringLiteral` in the `"ALG/MODE/PADDING"` or `"ALG"` format
|
* A `StringLiteral` in the `"ALG/MODE/PADDING"` or `"ALG"` format
|
||||||
*/
|
*/
|
||||||
@@ -345,7 +372,7 @@ module JCAModel {
|
|||||||
override KeyOpAlg::AlgorithmType getAlgorithmType() {
|
override KeyOpAlg::AlgorithmType getAlgorithmType() {
|
||||||
if cipher_name_to_type_known(_, super.getAlgorithmName())
|
if cipher_name_to_type_known(_, super.getAlgorithmName())
|
||||||
then cipher_name_to_type_known(result, super.getAlgorithmName())
|
then cipher_name_to_type_known(result, super.getAlgorithmName())
|
||||||
else result instanceof KeyOpAlg::TUnknownKeyOperationAlgorithmType
|
else result instanceof KeyOpAlg::TOtherKeyOperationAlgorithmType
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getKeySizeFixed() {
|
override int getKeySizeFixed() {
|
||||||
@@ -1639,6 +1666,196 @@ module JCAModel {
|
|||||||
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() { none() }
|
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() { none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signatures
|
||||||
|
*/
|
||||||
|
module SignatureKnownAlgorithmToConsumerConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SignatureStringLiteral }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
sink = any(SignatureAlgorithmValueConsumer call).getInputNode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module SignatureKnownAlgorithmToConsumerFlow =
|
||||||
|
TaintTracking::Global<SignatureKnownAlgorithmToConsumerConfig>;
|
||||||
|
|
||||||
|
class SignatureGetInstanceCall extends MethodCall {
|
||||||
|
SignatureGetInstanceCall() {
|
||||||
|
this.getCallee().hasQualifiedName("java.security", "Signature", "getInstance")
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr getAlgorithmArg() { result = this.getArgument(0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
class SignatureGetInstanceAlgorithmValueConsumer extends SignatureAlgorithmValueConsumer instanceof Expr
|
||||||
|
{
|
||||||
|
SignatureGetInstanceAlgorithmValueConsumer() {
|
||||||
|
this = any(SignatureGetInstanceCall c).getAlgorithmArg()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Crypto::ConsumerInputDataFlowNode getInputNode() { result.asExpr() = this }
|
||||||
|
|
||||||
|
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||||
|
result.(SignatureStringLiteralAlgorithmInstance).getConsumer() = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SignatureStringLiteral extends StringLiteral {
|
||||||
|
SignatureStringLiteral() { signature_names(this.getValue()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
class SignatureStringLiteralAlgorithmInstance extends Crypto::KeyOperationAlgorithmInstance instanceof SignatureStringLiteral
|
||||||
|
{
|
||||||
|
SignatureAlgorithmValueConsumer consumer;
|
||||||
|
|
||||||
|
SignatureStringLiteralAlgorithmInstance() {
|
||||||
|
SignatureKnownAlgorithmToConsumerFlow::flow(DataFlow::exprNode(this), consumer.getInputNode())
|
||||||
|
}
|
||||||
|
|
||||||
|
SignatureAlgorithmValueConsumer getConsumer() { result = consumer }
|
||||||
|
|
||||||
|
override string getRawAlgorithmName() { result = super.getValue() }
|
||||||
|
|
||||||
|
override Crypto::KeyOpAlg::AlgorithmType getAlgorithmType() {
|
||||||
|
if signature_name_to_type_known(_, super.getValue())
|
||||||
|
then signature_name_to_type_known(result, super.getValue())
|
||||||
|
else result = Crypto::KeyOpAlg::TOtherKeyOperationAlgorithmType()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
|
||||||
|
// TODO: trace to any key size initializer?
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
override int getKeySizeFixed() {
|
||||||
|
// TODO: are there known fixed key sizes to consider?
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() { none() }
|
||||||
|
|
||||||
|
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() { none() }
|
||||||
|
}
|
||||||
|
|
||||||
|
class SignatureHashAlgorithmInstance extends Crypto::HashAlgorithmInstance instanceof SignatureStringLiteralAlgorithmInstance
|
||||||
|
{
|
||||||
|
Crypto::THashType hashType;
|
||||||
|
int digestLength;
|
||||||
|
|
||||||
|
SignatureHashAlgorithmInstance() {
|
||||||
|
hashType = signature_name_to_hash_type_known(this.(StringLiteral).getValue(), digestLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getRawHashAlgorithmName() { result = this.(StringLiteral).getValue() }
|
||||||
|
|
||||||
|
override Crypto::THashType getHashFamily() { result = hashType }
|
||||||
|
|
||||||
|
override int getFixedDigestLength() { result = digestLength }
|
||||||
|
}
|
||||||
|
|
||||||
|
class SignatureInitCall extends MethodCall {
|
||||||
|
SignatureInitCall() {
|
||||||
|
this.getCallee().hasQualifiedName("java.security", "Signature", ["initSign", "initVerify"])
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr getKeyArg() {
|
||||||
|
result = this.getArgument(0)
|
||||||
|
// TODO: verify can take in a certificate too?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SignatureOperationCall extends MethodCall {
|
||||||
|
SignatureOperationCall() {
|
||||||
|
this.getMethod().hasQualifiedName("java.security", "Signature", ["update", "sign", "verify"])
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isIntermediate() { super.getMethod().getName() = "update" }
|
||||||
|
|
||||||
|
Expr getMsgInput() { result = this.getArgument(0) and this.getMethod().getName() = "update" }
|
||||||
|
|
||||||
|
Expr getSignatureOutput() {
|
||||||
|
// no args, the signature is returned
|
||||||
|
result = this and this.getMethod().getName() = "sign" and not exists(this.getArgument(0))
|
||||||
|
or
|
||||||
|
// with args, the signature is written to the arg
|
||||||
|
result = this.getArgument(0) and this.getMethod().getName() = "sign"
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr getSignatureInput() {
|
||||||
|
result = this.getArgument(0) and this.getMethod().getName() = "verify"
|
||||||
|
}
|
||||||
|
|
||||||
|
Crypto::KeyOperationSubtype getSubtype() {
|
||||||
|
result instanceof Crypto::TSignMode and this.getMethod().getName() = "sign"
|
||||||
|
or
|
||||||
|
result instanceof Crypto::TVerifyMode and this.getMethod().getName() = "verify"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SignatureOperationinstance extends Crypto::SignatureOperationInstance instanceof SignatureOperationCall
|
||||||
|
{
|
||||||
|
SignatureOperationinstance() {
|
||||||
|
// exclude update (only include sign and verify)
|
||||||
|
not super.isIntermediate()
|
||||||
|
}
|
||||||
|
|
||||||
|
SignatureGetInstanceCall getInstantiationCall() {
|
||||||
|
result = SignatureFlowAnalysisImpl::getInstantiationFromUse(this, _, _)
|
||||||
|
}
|
||||||
|
|
||||||
|
SignatureInitCall getInitCall() {
|
||||||
|
result = SignatureFlowAnalysisImpl::getInitFromUse(this, _, _)
|
||||||
|
}
|
||||||
|
|
||||||
|
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
||||||
|
result.asExpr() = super.getMsgInput() or
|
||||||
|
result.asExpr() =
|
||||||
|
SignatureFlowAnalysisImpl::getAnIntermediateUseFromFinalUse(this, _, _).getMsgInput()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
||||||
|
result.asExpr() = this.getInitCall().getKeyArg()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||||
|
result = this.getInstantiationCall().getAlgorithmArg()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
||||||
|
result.asExpr() = super.getSignatureOutput() or
|
||||||
|
result.asExpr() =
|
||||||
|
SignatureFlowAnalysisImpl::getAnIntermediateUseFromFinalUse(this, _, _).getSignatureOutput()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
|
||||||
|
// TODO: RSASSA-PSS literal sets hashes differently, through a ParameterSpec
|
||||||
|
result = this.getInstantiationCall().getAlgorithmArg()
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate hasHashAlgorithmConsumer() {
|
||||||
|
// All jca signature algorithms specify a hash unless explicitly set as "NONEwith..."
|
||||||
|
exists(SignatureStringLiteralAlgorithmInstance i |
|
||||||
|
i.getConsumer() = this.getAnAlgorithmValueConsumer() and
|
||||||
|
not i.getRawAlgorithmName().toUpperCase().matches("NONEwith%".toUpperCase())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override Crypto::KeyOperationSubtype getKeyOperationSubtype() { result = super.getSubtype() }
|
||||||
|
|
||||||
|
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() { none() }
|
||||||
|
|
||||||
|
override Crypto::ConsumerInputDataFlowNode getSignatureConsumer() {
|
||||||
|
result.asExpr() = super.getSignatureInput() or
|
||||||
|
result.asExpr() =
|
||||||
|
SignatureFlowAnalysisImpl::getAnIntermediateUseFromFinalUse(this, _, _).getSignatureInput()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module SignatureFlowAnalysisImpl =
|
||||||
|
GetInstanceInitUseFlowAnalysis<SignatureGetInstanceCall, SignatureInitCall,
|
||||||
|
SignatureOperationCall>;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Elliptic Curves (EC)
|
* Elliptic Curves (EC)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ module Types {
|
|||||||
TSignature(TSignatureAlgorithmType t) or
|
TSignature(TSignatureAlgorithmType t) or
|
||||||
TMac(TMacAlgorithmType t) or
|
TMac(TMacAlgorithmType t) or
|
||||||
TKeyEncapsulation(TKemAlgorithmType t) or
|
TKeyEncapsulation(TKemAlgorithmType t) or
|
||||||
TUnknownKeyOperationAlgorithmType()
|
TOtherKeyOperationAlgorithmType()
|
||||||
|
|
||||||
// Parameterized algorithm types
|
// Parameterized algorithm types
|
||||||
newtype TSymmetricCipherType =
|
newtype TSymmetricCipherType =
|
||||||
@@ -64,7 +64,7 @@ module Types {
|
|||||||
newtype TCipherStructureType =
|
newtype TCipherStructureType =
|
||||||
Block() or
|
Block() or
|
||||||
Stream() or
|
Stream() or
|
||||||
UnknownCipherStructureType()
|
OtherCipherStructureType()
|
||||||
|
|
||||||
class CipherStructureType extends TCipherStructureType {
|
class CipherStructureType extends TCipherStructureType {
|
||||||
string toString() {
|
string toString() {
|
||||||
@@ -72,7 +72,7 @@ module Types {
|
|||||||
or
|
or
|
||||||
result = "Stream" and this = Stream()
|
result = "Stream" and this = Stream()
|
||||||
or
|
or
|
||||||
result = "Unknown" and this = UnknownCipherStructureType()
|
result = "Unknown" and this = OtherCipherStructureType()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ module Types {
|
|||||||
or
|
or
|
||||||
type = OtherSymmetricCipherType() and
|
type = OtherSymmetricCipherType() and
|
||||||
name = "UnknownSymmetricCipher" and
|
name = "UnknownSymmetricCipher" and
|
||||||
s = UnknownCipherStructureType()
|
s = OtherCipherStructureType()
|
||||||
}
|
}
|
||||||
|
|
||||||
class AlgorithmType extends TAlgorithm {
|
class AlgorithmType extends TAlgorithm {
|
||||||
@@ -157,7 +157,7 @@ module Types {
|
|||||||
this = TMac(OtherMacAlgorithmType()) and result = "UnknownMac"
|
this = TMac(OtherMacAlgorithmType()) and result = "UnknownMac"
|
||||||
or
|
or
|
||||||
// Unknown
|
// Unknown
|
||||||
this = TUnknownKeyOperationAlgorithmType() and result = "Unknown"
|
this = TOtherKeyOperationAlgorithmType() and result = "Unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
int getImplicitKeySize() {
|
int getImplicitKeySize() {
|
||||||
|
|||||||
Reference in New Issue
Block a user