2222 */
2323
2424import go
25+ import semmle.go.security.InsecureFeatureFlag:: InsecureFeatureFlag
2526
2627/**
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` .
2930 */
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 )
4633 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
5135 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 ) )
8137}
8238
8339/**
84- * Gets a control-flow node that represents a (likely) feature-flag check for certificate checking .
40+ * Flags suggesting a deliberately insecure certificate setup .
8541 */
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+ }
8849}
8950
9051/**
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.
9353 */
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 ( )
10074}
10175
10276from Write w , DataFlow:: Node base , Field f , DataFlow:: Node rhs
@@ -105,14 +79,14 @@ where
10579 f .hasQualifiedName ( "crypto/tls" , "Config" , "InsecureSkipVerify" ) and
10680 rhs .getBoolValue ( ) = true and
10781 // exclude writes guarded by a feature flag
108- not getAFeatureFlagCheck ( ) .dominatesNode ( w ) and
82+ not [ getASecurityFeatureFlagCheck ( ) , getAnInsecureCertificateCheck ( ) ] .dominatesNode ( w ) and
10983 // exclude results in functions whose name documents the insecurity
11084 not exists ( FuncDef fn | fn = w .getRoot ( ) |
111- isFeatureFlagName ( fn .getEnclosingFunction * ( ) .getName ( ) )
85+ isSecurityOrCertificateConfigFlag ( fn .getEnclosingFunction * ( ) .getName ( ) )
11286 ) and
11387 // exclude results that flow into a field/variable whose name documents the insecurity
11488 not exists ( ValueEntity e , DataFlow:: Node init |
115- isFeatureFlagName ( e .getName ( ) ) and
89+ isSecurityOrCertificateConfigFlag ( e .getName ( ) ) and
11690 any ( Write w2 ) .writes ( e , init ) and
11791 becomesPartOf * ( base , init )
11892 ) and
0 commit comments