1212 */
1313
1414import go
15- import DataFlow:: PathGraph
1615import semmle.go.security.InsecureFeatureFlag:: InsecureFeatureFlag
1716
1817/**
@@ -55,13 +54,11 @@ int getATlsVersion() { result = getASecureTlsVersion() or isInsecureTlsVersion(r
5554 * A taint-tracking configuration for tracking flow from TLS versions to the
5655 * `tls.Config.MinVersion` and `tls.Config.MaxVersion` fields.
5756 */
58- class TlsVersionFlowConfig extends TaintTracking:: Configuration {
59- TlsVersionFlowConfig ( ) { this = "TlsVersionFlowConfig" }
60-
57+ module TlsVersionFlowConfig implements DataFlow:: ConfigSig {
6158 /**
6259 * Holds if `source` is a TLS version source yielding value `val`.
6360 */
64- predicate intIsSource ( DataFlow:: Node source , int val ) {
61+ additional predicate intIsSource ( DataFlow:: Node source , int val ) {
6562 val = source .getIntValue ( ) and
6663 val = getATlsVersion ( ) and
6764 not DataFlow:: isReturnedWithError ( source )
@@ -70,43 +67,43 @@ class TlsVersionFlowConfig extends TaintTracking::Configuration {
7067 /**
7168 * Holds if `fieldWrite` writes `sink` to `base`.`fld`, where `fld` is a TLS version field.
7269 */
73- predicate isSink ( DataFlow:: Node sink , Field fld , DataFlow:: Node base , Write fieldWrite ) {
70+ additional predicate isSink ( DataFlow:: Node sink , Field fld , DataFlow:: Node base , Write fieldWrite ) {
7471 fld .hasQualifiedName ( "crypto/tls" , "Config" , [ "MinVersion" , "MaxVersion" ] ) and
7572 fieldWrite .writesField ( base , fld , sink )
7673 }
7774
78- override predicate isSource ( DataFlow:: Node source ) { this . intIsSource ( source , _) }
75+ predicate isSource ( DataFlow:: Node source ) { intIsSource ( source , _) }
7976
80- override predicate isSink ( DataFlow:: Node sink ) { this . isSink ( sink , _, _, _) }
77+ predicate isSink ( DataFlow:: Node sink ) { isSink ( sink , _, _, _) }
8178}
8279
80+ module TlsVersionFlow = TaintTracking:: Global< TlsVersionFlowConfig > ;
81+
8382/**
8483 * Holds if `config` exhibits a secure TLS version flowing from `source` to `sink`, which flows into `fld`.
8584 */
86- predicate secureTlsVersionFlow (
87- TlsVersionFlowConfig config , DataFlow:: PathNode source , DataFlow:: PathNode sink , Field fld
88- ) {
85+ predicate secureTlsVersionFlow ( DataFlow:: Node source , DataFlow:: Node sink , Field fld ) {
8986 exists ( int version |
90- config . hasFlowPath ( source , sink ) and
91- config . intIsSource ( source . getNode ( ) , version ) and
87+ TlsVersionFlow :: flow ( source , sink ) and
88+ TlsVersionFlowConfig :: intIsSource ( source , version ) and
9289 not isInsecureTlsVersion ( version , _, fld .getName ( ) )
9390 )
9491}
9592
9693/**
9794 * Holds if a secure TLS version reaches `sink`, which flows into `fld`.
9895 */
99- predicate secureTlsVersionFlowsToSink ( DataFlow:: PathNode sink , Field fld ) {
100- secureTlsVersionFlow ( _, _ , sink , fld )
96+ predicate secureTlsVersionFlowsToSink ( DataFlow:: Node sink , Field fld ) {
97+ secureTlsVersionFlow ( _, sink , fld )
10198}
10299
103100/**
104101 * Holds if a secure TLS version may reach `accessPath`.`fld`
105102 */
106103predicate secureTlsVersionFlowsToField ( SsaWithFields accessPath , Field fld ) {
107- exists ( TlsVersionFlowConfig config , DataFlow:: PathNode sink , DataFlow:: Node base |
108- secureTlsVersionFlow ( config , _, sink , fld ) and
109- config . isSink ( sink . getNode ( ) , fld , base , _) and
104+ exists ( DataFlow:: Node sink , DataFlow:: Node base |
105+ secureTlsVersionFlow ( _, sink , fld ) and
106+ TlsVersionFlowConfig :: isSink ( sink , fld , base , _) and
110107 accessPath .getAUse ( ) = base
111108 )
112109}
@@ -124,17 +121,18 @@ DataFlow::Node nodeOrDeref(DataFlow::Node node) {
124121 * to a field of `base`. `message` describes the specific problem found.
125122 */
126123predicate isInsecureTlsVersionFlow (
127- DataFlow:: PathNode source , DataFlow:: PathNode sink , string message , DataFlow:: Node base
124+ TlsVersionFlow:: PathNode source , TlsVersionFlow:: PathNode sink , string message ,
125+ DataFlow:: Node base
128126) {
129- exists ( TlsVersionFlowConfig cfg , int version , Field fld |
130- cfg . hasFlowPath ( source , sink ) and
131- cfg . intIsSource ( source .getNode ( ) , version ) and
132- cfg . isSink ( sink .getNode ( ) , fld , base , _) and
127+ exists ( int version , Field fld |
128+ TlsVersionFlow :: flowPath ( source , sink ) and
129+ TlsVersionFlowConfig :: intIsSource ( source .getNode ( ) , version ) and
130+ TlsVersionFlowConfig :: isSink ( sink .getNode ( ) , fld , base , _) and
133131 isInsecureTlsVersion ( version , _, fld .getName ( ) ) and
134132 // Exclude cases where a secure TLS version can also flow to the same
135133 // sink, or to different sinks that refer to the same base and field,
136134 // which suggests a configurable security mode.
137- not secureTlsVersionFlowsToSink ( sink , fld ) and
135+ not secureTlsVersionFlowsToSink ( sink . getNode ( ) , fld ) and
138136 not exists ( SsaWithFields insecureAccessPath , SsaWithFields secureAccessPath |
139137 nodeOrDeref ( insecureAccessPath .getAUse ( ) ) = base and
140138 secureAccessPath = insecureAccessPath .similar ( )
@@ -156,13 +154,11 @@ predicate isInsecureTlsVersionFlow(
156154 * A taint-tracking configuration for tracking flow from insecure TLS cipher
157155 * suites into a `tls.Config` struct, to the `CipherSuites` field.
158156 */
159- class TlsInsecureCipherSuitesFlowConfig extends TaintTracking:: Configuration {
160- TlsInsecureCipherSuitesFlowConfig ( ) { this = "TlsInsecureCipherSuitesFlowConfig" }
161-
157+ module TlsInsecureCipherSuitesFlowConfig implements DataFlow:: ConfigSig {
162158 /**
163159 * Holds if `source` reads an insecure TLS cipher suite named `suiteName`.
164160 */
165- predicate isSourceValueEntity ( DataFlow:: Node source , string suiteName ) {
161+ additional predicate isSourceValueEntity ( DataFlow:: Node source , string suiteName ) {
166162 exists ( DataFlow:: ValueEntity val |
167163 val .hasQualifiedName ( "crypto/tls" , suiteName ) and
168164 suiteName =
@@ -179,52 +175,58 @@ class TlsInsecureCipherSuitesFlowConfig extends TaintTracking::Configuration {
179175 /**
180176 * Holds if `source` represents the result of `tls.InsecureCipherSuites()`.
181177 */
182- predicate isSourceInsecureCipherSuites ( DataFlow:: Node source ) {
178+ additional predicate isSourceInsecureCipherSuites ( DataFlow:: Node source ) {
183179 exists ( Function insecureCipherSuites |
184180 insecureCipherSuites .hasQualifiedName ( "crypto/tls" , "InsecureCipherSuites" )
185181 |
186182 source = insecureCipherSuites .getACall ( ) .getResult ( )
187183 )
188184 }
189185
190- override predicate isSource ( DataFlow:: Node source ) {
191- this . isSourceInsecureCipherSuites ( source )
186+ predicate isSource ( DataFlow:: Node source ) {
187+ isSourceInsecureCipherSuites ( source )
192188 or
193- this . isSourceValueEntity ( source , _)
189+ isSourceValueEntity ( source , _)
194190 }
195191
196192 /**
197193 * Holds if `fieldWrite` writes `sink` to `base`.`fld`, and `fld` is `tls.Config.CipherSuites`.
198194 */
199- predicate isSink ( DataFlow:: Node sink , Field fld , DataFlow:: Node base , Write fieldWrite ) {
195+ additional predicate isSink ( DataFlow:: Node sink , Field fld , DataFlow:: Node base , Write fieldWrite ) {
200196 fld .hasQualifiedName ( "crypto/tls" , "Config" , "CipherSuites" ) and
201197 fieldWrite .writesField ( base , fld , sink )
202198 }
203199
204- override predicate isSink ( DataFlow:: Node sink ) { this . isSink ( sink , _, _, _) }
200+ predicate isSink ( DataFlow:: Node sink ) { isSink ( sink , _, _, _) }
205201
206202 /**
207203 * Declare sinks as out-sanitizers in order to avoid producing superfluous paths where a cipher
208204 * is written to CipherSuites, then the list is further extended with either safe or tainted
209205 * suites.
210206 */
211- override predicate isSanitizerOut ( DataFlow:: Node node ) {
212- super .isSanitizerOut ( node ) or this .isSink ( node )
213- }
207+ predicate isBarrierOut ( DataFlow:: Node node ) { isSink ( node ) }
214208}
215209
210+ module TlsInsecureCipherSuitesFlow = TaintTracking:: Global< TlsInsecureCipherSuitesFlowConfig > ;
211+
216212/**
217213 * Holds if an insecure TLS cipher suite flows from `source` to `sink`, where `sink`
218214 * is written to the CipherSuites list of a `tls.Config` instance. `message` describes
219215 * the exact problem found.
220216 */
221- predicate isInsecureTlsCipherFlow ( DataFlow:: PathNode source , DataFlow:: PathNode sink , string message ) {
222- exists ( TlsInsecureCipherSuitesFlowConfig cfg | cfg .hasFlowPath ( source , sink ) |
223- exists ( string name | cfg .isSourceValueEntity ( source .getNode ( ) , name ) |
217+ predicate isInsecureTlsCipherFlow (
218+ TlsInsecureCipherSuitesFlow:: PathNode source , TlsInsecureCipherSuitesFlow:: PathNode sink ,
219+ string message
220+ ) {
221+ TlsInsecureCipherSuitesFlow:: flowPath ( source , sink ) and
222+ (
223+ exists ( string name |
224+ TlsInsecureCipherSuitesFlowConfig:: isSourceValueEntity ( source .getNode ( ) , name )
225+ |
224226 message = "Use of an insecure cipher suite: " + name + "."
225227 )
226228 or
227- cfg . isSourceInsecureCipherSuites ( source .getNode ( ) ) and
229+ TlsInsecureCipherSuitesFlowConfig :: isSourceInsecureCipherSuites ( source .getNode ( ) ) and
228230 message = "Use of an insecure cipher suite."
229231 )
230232}
@@ -260,11 +262,17 @@ FlagKind securityOrTlsVersionFlag() {
260262 result = any ( LegacyTlsVersionFlag f )
261263}
262264
263- from DataFlow:: PathNode source , DataFlow:: PathNode sink , string message
265+ module Flow =
266+ DataFlow:: MergePathGraph< TlsVersionFlow:: PathNode , TlsInsecureCipherSuitesFlow:: PathNode ,
267+ TlsVersionFlow:: PathGraph , TlsInsecureCipherSuitesFlow:: PathGraph > ;
268+
269+ import Flow:: PathGraph
270+
271+ from Flow:: PathNode source , Flow:: PathNode sink , string message
264272where
265273 (
266- isInsecureTlsVersionFlow ( source , sink , message , _) or
267- isInsecureTlsCipherFlow ( source , sink , message )
274+ isInsecureTlsVersionFlow ( source . asPathNode1 ( ) , sink . asPathNode1 ( ) , message , _) or
275+ isInsecureTlsCipherFlow ( source . asPathNode2 ( ) , sink . asPathNode2 ( ) , message )
268276 ) and
269277 // Exclude sources or sinks guarded by a feature or legacy flag
270278 not [ getASecurityFeatureFlagCheck ( ) , getALegacyTlsVersionCheck ( ) ]
0 commit comments