-
Notifications
You must be signed in to change notification settings - Fork 1.8k
C++: New query for SSL certificates not checked #7243
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't looked at any of the LGTM results yet. But I have a couple of code comments.
* `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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intead of rolling our own control-flow analysis here, could we instead use StackVariableReachability
? Then isSource
could be the call to SSL_get_peer_certificate
, isSink
could be the exit of the function, and isBarrier
could be a call to SSL_get_verify_result
.
Would that work?
It may be difficult to fit the certIsZero
barrier into SSL_get_peer_certificate
, but I think it's doable by having one StackVariableReachability
for each call to SSL_get_peer_certificate
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried a couple of libraries that didn't quite fit the problem, I may have overlooked StackVariableReachability
.. Trying it now...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be difficult to fit the
certIsZero
barrier intoSSL_get_peer_certificate
, but I think it's doable by having oneStackVariableReachability
for each call toSSL_get_peer_certificate
.
This turns out not to be a major issue, the existing GVN logic finds appropriate guards on certificates returned by SSL_get_peer_certificate
, and I've never seen more than one certificate being used at once (in which case we'd have to worry about which certificate it is).
What is an issue is that the certIsZero
barrier needs to be a barrier edge, not a barrier node. StackVariableReachability
does not appear to support barrier edges and I haven't found a sufficient workaround for this yet. I suppose I could add it as a new feature, but that will then require a lot of testing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. I appreciate that you looked into it! Let's postpone converting the logic to StackVariableReachability
to a later point, then.
// if (cert) { } | ||
guard = cert and | ||
node1 = guard and | ||
node2 = guard.getAFalseSuccessor() | ||
or | ||
// if (!cert) { | ||
node1 = guard.getParent() and | ||
node2 = guard.getParent().(NotExpr).getATrueSuccessor() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could these cases not be covered by using guard.controls
? That might be able to solve the FP in test2_11
(and in principle the one in test2_9
as well, but IIRC the GuardCondition
s class specifically doesn't handle this case very well).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've pushed an improved version using guard.controls
(and fixing some other issues). It's a bit tricky because guards gives the basic blocks that may be entered only if the guard goes a particular way, whereas we want to be able to handle blocks that have more than one route in, e.g.
cert = SSL_get_peer_certificate(ssl);
if (cert)
{
result = SSL_get_verify_result(ssl);
...
}
// here
In the case above here
is good because one path to it has cert = 0
, the other has a call to SSL_get_verify_result
- not because of either fact on its own. As such the code is still somewhat special-cased rather than just letting guards do its thing.
Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
Pushed some improvements:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
This is the second of two new queries for CWE-295: Improper Certificate Validation.
Results:
SSL_get_peer_certificate
.Precision:
@medium
, for review after looking at the LGTM results in more depth.Performance:
kamailio_kamailio
andchakra-core
(performance is great with a warmed up cache).