mirror of
https://github.com/github/codeql.git
synced 2026-05-03 20:58:03 +02:00
C++: Prototype SSL result not checked query.
This commit is contained in:
118
cpp/ql/src/Security/CWE/CWE-295/SSLResultNotChecked.ql
Normal file
118
cpp/ql/src/Security/CWE/CWE-295/SSLResultNotChecked.ql
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @name TODO
|
||||
* @description TODO
|
||||
* @kind problem
|
||||
* @problem.severity TODO
|
||||
* @security-severity TODO
|
||||
* @precision TODO
|
||||
* @id TODO
|
||||
* @tags TODO
|
||||
*/
|
||||
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
//import semmle.code.cpp.controlflow.Guards
|
||||
import semmle.code.cpp.controlflow.IRGuards
|
||||
|
||||
/**
|
||||
* A call to `SSL_get_peer_certificate`.
|
||||
*/
|
||||
class SSLGetPeerCertificateCall extends FunctionCall {
|
||||
SSLGetPeerCertificateCall() {
|
||||
getTarget().getName() = "SSL_get_peer_certificate" // SSL_get_peer_certificate(ssl)
|
||||
}
|
||||
|
||||
// TODO: getSSLArg?
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `SSL_get_verify_result`.
|
||||
*/
|
||||
class SSLGetVerifyResultCall extends FunctionCall {
|
||||
SSLGetVerifyResultCall() {
|
||||
getTarget().getName() = "SSL_get_verify_result" // SSL_get_peer_certificate(ssl)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSL object passed into `SSL_get_peer_certificate` is checked with
|
||||
* `SSL_get_verify_result` entering `node`.
|
||||
*/
|
||||
predicate resultIsChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
|
||||
exists(Expr ssl, SSLGetVerifyResultCall check |
|
||||
ssl = globalValueNumber(getCertCall.getArgument(0)).getAnExpr() and
|
||||
ssl = check.getArgument(0) and
|
||||
node = check
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the certificate returned by `SSL_get_peer_certificate` is found to be
|
||||
* `0` on the edge `node1` to `node2`.
|
||||
*/
|
||||
predicate certIsZero(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node1, ControlFlowNode node2) {
|
||||
exists(GuardCondition guard, Expr cert |
|
||||
cert = globalValueNumber(getCertCall).getAnExpr() and
|
||||
(
|
||||
exists(Expr zero |
|
||||
zero.getValue().toInt() = 0 and
|
||||
node1 = guard and
|
||||
(
|
||||
(
|
||||
guard.comparesEq(cert, zero, 0, true, true) and // if (cert == zero) {
|
||||
node2 = guard.getATrueSuccessor()
|
||||
) or (
|
||||
guard.comparesEq(cert, zero, 0, false, true) and // if (cert != zero) { }
|
||||
node2 = guard.getAFalseSuccessor()
|
||||
)
|
||||
)
|
||||
) or (
|
||||
guard = cert and // if (cert) { }
|
||||
node1 = guard and
|
||||
node2 = guard.getAFalseSuccessor()
|
||||
) or (
|
||||
node1 = guard.getParent() and
|
||||
node2 = guard.getParent().(NotExpr).getATrueSuccessor() // if (!cert) {
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSL object passed into `SSL_get_peer_certificate` has not been checked with
|
||||
* `SSL_get_verify_result` at `node`. Note that this is only computed at the call to
|
||||
* `SSL_get_peer_certificate` and at the start and end of `BasicBlock`s.
|
||||
*/
|
||||
predicate certNotChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
|
||||
(
|
||||
// cert is not checked at the call to `SSL_get_peer_certificate`
|
||||
node = getCertCall
|
||||
) or exists(BasicBlock bb, int pos |
|
||||
// flow to end of a `BasicBlock`
|
||||
certNotChecked(getCertCall, bb.getNode(pos)) and
|
||||
node = bb.getEnd() and
|
||||
|
||||
// check for barrier node
|
||||
not exists(int pos2 |
|
||||
pos2 > pos and
|
||||
resultIsChecked(getCertCall, bb.getNode(pos2))
|
||||
)
|
||||
) or exists(BasicBlock pred, BasicBlock bb |
|
||||
// flow from the end of one `BasicBlock` to the beginning of a successor
|
||||
certNotChecked(getCertCall, pred.getEnd()) and
|
||||
bb = pred.getASuccessor() and
|
||||
node = bb.getStart() and
|
||||
|
||||
// check for barrier bb
|
||||
not certIsZero(getCertCall, pred.getEnd(), bb.getStart())
|
||||
)
|
||||
}
|
||||
|
||||
from
|
||||
SSLGetPeerCertificateCall getCertCall, ControlFlowNode node
|
||||
where
|
||||
certNotChecked(getCertCall, node) and
|
||||
node instanceof Function // (function exit)
|
||||
select
|
||||
getCertCall, "This " + getCertCall.toString() + " is not followed by a call to SSL_get_verify_result."
|
||||
@@ -0,0 +1,4 @@
|
||||
| test2.cpp:13:13:13:36 | call to SSL_get_peer_certificate | This call to SSL_get_peer_certificate is not followed by a call to SSL_get_verify_result. |
|
||||
| test2.cpp:28:13:28:36 | call to SSL_get_peer_certificate | This call to SSL_get_peer_certificate is not followed by a call to SSL_get_verify_result. |
|
||||
| test2.cpp:61:9:61:32 | call to SSL_get_peer_certificate | This call to SSL_get_peer_certificate is not followed by a call to SSL_get_verify_result. |
|
||||
| test2.cpp:89:9:89:32 | call to SSL_get_peer_certificate | This call to SSL_get_peer_certificate is not followed by a call to SSL_get_verify_result. |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-295/SSLResultNotChecked.ql
|
||||
147
cpp/ql/test/query-tests/Security/CWE/CWE-295/test2.cpp
Normal file
147
cpp/ql/test/query-tests/Security/CWE/CWE-295/test2.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
|
||||
struct SSL {
|
||||
// ...
|
||||
};
|
||||
|
||||
int SSL_get_peer_certificate(const SSL *ssl);
|
||||
int SSL_get_verify_result(const SSL *ssl);
|
||||
|
||||
bool maybe();
|
||||
|
||||
bool test2_1(SSL *ssl)
|
||||
{
|
||||
int cert = SSL_get_peer_certificate(ssl); // BAD (SSL_get_verify_result is never called)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test2_2(SSL *ssl)
|
||||
{
|
||||
int cert = SSL_get_peer_certificate(ssl); // GOOD (SSL_get_verify_result is always called)
|
||||
int result = SSL_get_verify_result(ssl);
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
bool test2_3(SSL *ssl)
|
||||
{
|
||||
int cert = SSL_get_peer_certificate(ssl); // BAD (SSL_get_verify_result may not be called)
|
||||
|
||||
if (maybe())
|
||||
{
|
||||
int result = SSL_get_verify_result(ssl);
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test2_4(SSL *ssl)
|
||||
{
|
||||
int cert, result;
|
||||
|
||||
cert = SSL_get_peer_certificate(ssl); // GOOD (SSL_get_verify_result is called when there is a cert)
|
||||
if (cert != 0)
|
||||
{
|
||||
result = SSL_get_verify_result(ssl);
|
||||
if (result == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool test2_5(SSL *ssl)
|
||||
{
|
||||
int cert, result;
|
||||
|
||||
cert = SSL_get_peer_certificate(ssl); // BAD (SSL_get_verify_result is not used reliably)
|
||||
if ((cert != 0) && (maybe()))
|
||||
{
|
||||
result = SSL_get_verify_result(ssl);
|
||||
if (result == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool test2_6(SSL *ssl)
|
||||
{
|
||||
int cert;
|
||||
|
||||
cert = SSL_get_peer_certificate(ssl); // GOOD (SSL_get_verify_result is called when there is a cert)
|
||||
if (cert == 0) return false;
|
||||
if (SSL_get_verify_result(ssl) != 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test2_7(SSL *ssl)
|
||||
{
|
||||
int cert;
|
||||
|
||||
cert = SSL_get_peer_certificate(ssl); // BAD (SSL_get_verify_result is only called when there is not a cert)
|
||||
if (cert != 0) return false;
|
||||
if (SSL_get_verify_result(ssl) != 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test2_8(SSL *ssl)
|
||||
{
|
||||
int cert;
|
||||
|
||||
cert = SSL_get_peer_certificate(ssl); // GOOD (SSL_get_verify_result is called when there is a cert) [FALSE POSITIVE]
|
||||
if (!cert) return false;
|
||||
if (!SSL_get_verify_result(ssl)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test2_9(SSL *ssl)
|
||||
{
|
||||
int cert;
|
||||
|
||||
cert = SSL_get_peer_certificate(ssl); // GOOD (SSL_get_verify_result is called when there is a cert) [FALSE POSITIVE]
|
||||
if ((!cert) || (SSL_get_verify_result(ssl) != 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test2_10(SSL *ssl)
|
||||
{
|
||||
int cert = SSL_get_peer_certificate(ssl); // GOOD (SSL_get_verify_result is called when there is a cert)
|
||||
|
||||
if (cert)
|
||||
{
|
||||
int result = SSL_get_verify_result(ssl);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test2_11(SSL *ssl)
|
||||
{
|
||||
int cert;
|
||||
|
||||
cert = SSL_get_peer_certificate(ssl); // GOOD (SSL_get_verify_result is called when there is a cert) [FALSE POSITIVE]
|
||||
|
||||
if ((cert) && (SSL_get_verify_result(ssl) == 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user