22
22
*/
23
23
24
24
import go
25
+ import semmle.go.security.InsecureFeatureFlag:: InsecureFeatureFlag
25
26
26
27
/**
27
- * Holds if `name` may be the name of a feature flag that controls whether certificate checking is
28
- * enabled .
28
+ * Holds if `part` becomes a part of `whole`, either by (local) data flow or by being incorporated
29
+ * into `whole` through having its address taken or being written to a field of `whole` .
29
30
*/
30
- bindingset [ name]
31
- predicate isFeatureFlagName ( string name ) {
32
- name .regexpMatch ( "(?i).*(secure|selfCert|selfSign|validat|verif|trust|(en|dis)able).*" )
33
- }
34
-
35
- /** Gets a global value number representing a (likely) feature flag for certificate checking. */
36
- GVN getAFeatureFlag ( ) {
37
- // a call like `cfg.disableVerification()`
38
- exists ( DataFlow:: CallNode c | isFeatureFlagName ( c .getTarget ( ) .getName ( ) ) |
39
- result = globalValueNumber ( c )
40
- )
41
- or
42
- // a variable or field like `insecure`
43
- exists ( ValueEntity flag | isFeatureFlagName ( flag .getName ( ) ) |
44
- result = globalValueNumber ( flag .getARead ( ) )
45
- )
31
+ predicate becomesPartOf ( DataFlow:: Node part , DataFlow:: Node whole ) {
32
+ DataFlow:: localFlow ( part , whole )
46
33
or
47
- // a string constant such as `"insecure"` or `"skipVerification"`
48
- exists ( DataFlow:: Node const | isFeatureFlagName ( const .getStringValue ( ) ) |
49
- result = globalValueNumber ( const )
50
- )
34
+ whole .( DataFlow:: AddressOperationNode ) .getOperand ( ) = part
51
35
or
52
- // track feature flags through various operations
53
- exists ( DataFlow:: Node flag | flag = getAFeatureFlag ( ) .getANode ( ) |
54
- // tuple destructurings
55
- result = globalValueNumber ( DataFlow:: extractTupleElement ( flag , _) )
56
- or
57
- // type casts
58
- exists ( DataFlow:: TypeCastNode tc |
59
- tc .getOperand ( ) = flag and
60
- result = globalValueNumber ( tc )
61
- )
62
- or
63
- // pointer dereferences
64
- exists ( DataFlow:: PointerDereferenceNode deref |
65
- deref .getOperand ( ) = flag and
66
- result = globalValueNumber ( deref )
67
- )
68
- or
69
- // calls like `os.Getenv("DISABLE_TLS_VERIFICATION")`
70
- exists ( DataFlow:: CallNode call |
71
- call .getAnArgument ( ) = flag and
72
- result = globalValueNumber ( call )
73
- )
74
- or
75
- // comparisons like `insecure == true`
76
- exists ( DataFlow:: EqualityTestNode eq |
77
- eq .getAnOperand ( ) = flag and
78
- result = globalValueNumber ( eq )
79
- )
80
- )
36
+ exists ( Write w | w .writesField ( whole .( DataFlow:: PostUpdateNode ) .getPreUpdateNode ( ) , _, part ) )
81
37
}
82
38
83
39
/**
84
- * Gets a control-flow node that represents a (likely) feature-flag check for certificate checking .
40
+ * Flags suggesting a deliberately insecure certificate setup .
85
41
*/
86
- ControlFlow:: ConditionGuardNode getAFeatureFlagCheck ( ) {
87
- result .ensures ( getAFeatureFlag ( ) .getANode ( ) , _)
42
+ class InsecureCertificateFlag extends FlagKind {
43
+ InsecureCertificateFlag ( ) { this = "insecureCertificate" }
44
+
45
+ bindingset [ result ]
46
+ override string getAFlagName ( ) {
47
+ result .regexpMatch ( "(?i).*(selfCert|selfSign|validat|verif|trust).*" )
48
+ }
88
49
}
89
50
90
51
/**
91
- * Holds if `part` becomes a part of `whole`, either by (local) data flow or by being incorporated
92
- * into `whole` through having its address taken or being written to a field of `whole`.
52
+ * Gets a control-flow node that represents a (likely) flag controlling an insecure certificate setup.
93
53
*/
94
- predicate becomesPartOf ( DataFlow:: Node part , DataFlow:: Node whole ) {
95
- DataFlow:: localFlow ( part , whole )
96
- or
97
- whole .( DataFlow:: AddressOperationNode ) .getOperand ( ) = part
98
- or
99
- exists ( Write w | w .writesField ( whole .( DataFlow:: PostUpdateNode ) .getPreUpdateNode ( ) , _, part ) )
54
+ ControlFlow:: ConditionGuardNode getAnInsecureCertificateCheck ( ) {
55
+ result .ensures ( any ( InsecureCertificateFlag f ) .getAFlag ( ) .getANode ( ) , _)
56
+ }
57
+
58
+ /**
59
+ * Returns flag kinds relevant to this query: a generic security feature flag, or one
60
+ * specifically controlling insecure certificate configuration.
61
+ */
62
+ FlagKind securityOrTlsVersionFlag ( ) {
63
+ result = any ( SecurityFeatureFlag f ) or
64
+ result = any ( InsecureCertificateFlag f )
65
+ }
66
+
67
+ /**
68
+ * Holds if `name` is (likely to be) a general security flag or one specifically controlling
69
+ * an insecure certificate setup.
70
+ */
71
+ bindingset [ name]
72
+ predicate isSecurityOrCertificateConfigFlag ( string name ) {
73
+ name = securityOrTlsVersionFlag ( ) .getAFlagName ( )
100
74
}
101
75
102
76
from Write w , DataFlow:: Node base , Field f , DataFlow:: Node rhs
@@ -105,14 +79,14 @@ where
105
79
f .hasQualifiedName ( "crypto/tls" , "Config" , "InsecureSkipVerify" ) and
106
80
rhs .getBoolValue ( ) = true and
107
81
// exclude writes guarded by a feature flag
108
- not getAFeatureFlagCheck ( ) .dominatesNode ( w ) and
82
+ not [ getASecurityFeatureFlagCheck ( ) , getAnInsecureCertificateCheck ( ) ] .dominatesNode ( w ) and
109
83
// exclude results in functions whose name documents the insecurity
110
84
not exists ( FuncDef fn | fn = w .getRoot ( ) |
111
- isFeatureFlagName ( fn .getEnclosingFunction * ( ) .getName ( ) )
85
+ isSecurityOrCertificateConfigFlag ( fn .getEnclosingFunction * ( ) .getName ( ) )
112
86
) and
113
87
// exclude results that flow into a field/variable whose name documents the insecurity
114
88
not exists ( ValueEntity e , DataFlow:: Node init |
115
- isFeatureFlagName ( e .getName ( ) ) and
89
+ isSecurityOrCertificateConfigFlag ( e .getName ( ) ) and
116
90
any ( Write w2 ) .writes ( e , init ) and
117
91
becomesPartOf * ( base , init )
118
92
) and
0 commit comments