-
Notifications
You must be signed in to change notification settings - Fork 282
Expand file tree
/
Copy pathBoostAsioMissingVerifyCallback.ql
More file actions
83 lines (71 loc) · 2.54 KB
/
BoostAsioMissingVerifyCallback.ql
File metadata and controls
83 lines (71 loc) · 2.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/**
* @name BoostAsioMissingVerifyCallback
* @kind problem
* @problem.severity recommendation
* @id cpp/boost-asio-missing-boost-verify-callback
* @tags security
* external/cwe/cwe-273
*/
/*
* The default `verify_callback` https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_verify.html
* does not compare CN/hostnames so a TLS client can be MITMed.
*
* The boost ASIO/SSL library also does not install a hostname verifier callback.
*
* False positives include intentionally skipping checking (for example as the result of
* configuration), using a server context, or using an uncommon strategy for inspecting certs.
*/
import cpp
predicate sslOrDetailNamespace(Namespace n) {
n.getQualifiedName() = "boost::asio::ssl" or
n.getQualifiedName() = "boost::asio::ssl::detail"
}
predicate sslStreamOrEngineType(UserType t) {
t.getSimpleName() = "stream" or
t.getSimpleName() = "engine" or
t.getSimpleName() = "context"
}
class AsioStreamType extends Type {
Type baseType;
AsioStreamType() {
(
// Consider shared_ptr, raw pointers, or base types.
baseType = this.(DerivedType).getBaseType() or
baseType = this.(UserType).getATemplateArgument+() or
baseType = this
) and
sslOrDetailNamespace(baseType.(UserType).getNamespace()) and
sslStreamOrEngineType(baseType)
}
}
class StreamSocketVariable extends Variable {
AsioStreamType type;
StreamSocketVariable() { this.getType() = type }
}
class SetVerifyModeFunctionCall extends FunctionCall {
SetVerifyModeFunctionCall() {
// This can be improved, false positives can be reduced by also checking namespace.
this.getTarget().hasName("set_verify_mode")
}
}
class SetVerifyCallbackFunctionCall extends FunctionCall {
SetVerifyCallbackFunctionCall() {
// This can be improved, false positives can be reduced by also checking namespace.
this.getTarget().hasName("set_verify_callback")
}
}
predicate callsSetVerifyCallback(StreamSocketVariable v) {
exists(SetVerifyCallbackFunctionCall fc, Expr e |
e = fc.getQualifier() and
v = e.(VariableAccess).getTarget()
)
}
from SetVerifyModeFunctionCall fc, StreamSocketVariable v
where
// There is most likely a better method than assuming the only namespace/simple-name
// child access is the qualifier.
v = fc.getQualifier().(VariableAccess).getTarget() and
not callsSetVerifyCallback(v)
select fc,
"boost::asio::ssl context calls set_verify_mode without a callback $@, if this is a client context then hostname validation may be missing",
v, "on the socket (" + v.getName() + ")"