@@ -262,7 +262,7 @@ func (p *processor) domainChecks(domain string) []func(*processor, string) error
262262 }
263263
264264 if ! direct {
265- checks = append (checks , (* processor ).checkSecurity )
265+ checks = append (checks , (* processor ).checkWellknownSecurityDNS )
266266 }
267267
268268 checks = append (checks ,
@@ -272,13 +272,6 @@ func (p *processor) domainChecks(domain string) []func(*processor, string) error
272272 (* processor ).checkListing ,
273273 )
274274
275- if ! direct {
276- checks = append (checks ,
277- (* processor ).checkWellknownMetadataReporter ,
278- (* processor ).checkDNSPathReporter ,
279- )
280- }
281-
282275 return checks
283276}
284277
@@ -1084,83 +1077,159 @@ func (p *processor) checkProviderMetadata(domain string) error {
10841077
10851078// checkSecurity checks the security.txt file by making HTTP request to fetch it.
10861079// It checks the existence of the CSAF field in the file content and tries to fetch
1087- // the value of this field. As a result of these a respective error messages are
1088- // passed to the badSecurity method in case of errors.
1089- // It returns nil if all checks are passed.
1090- func (p * processor ) checkSecurity (domain string ) error {
1080+ // the value of this field. Returns an empty string if no error was encountered,
1081+ // the errormessage otherwise.
1082+ func (p * processor ) checkSecurity (domain string ) string {
10911083
10921084 client := p .httpClient ()
1093- p .badSecurity .use ()
1094-
10951085 path := "https://" + domain + "/.well-known/security.txt"
10961086 res , err := client .Get (path )
10971087 if err != nil {
1098- p .badSecurity .error ("Fetching %s failed: %v" , path , err )
1099- return errContinue
1088+ return fmt .Sprintf ("Fetching %s failed: %v" , path , err )
11001089 }
11011090
11021091 if res .StatusCode != http .StatusOK {
1103- p . badSecurity . error ("Fetching %s failed. Status code %d (%s)" ,
1092+ return fmt . Sprintf ("Fetching %s failed. Status code %d (%s)" ,
11041093 path , res .StatusCode , res .Status )
1105- return errContinue
11061094 }
11071095
11081096 u , err := func () (string , error ) {
11091097 defer res .Body .Close ()
1110- lines := bufio .NewScanner (res .Body )
1111- for lines .Scan () {
1112- line := lines .Text ()
1113- if strings .HasPrefix (line , "CSAF:" ) {
1114- return strings .TrimSpace (line [6 :]), nil
1115- }
1098+ lines , err := csaf .ExtractProviderURL (res .Body , false )
1099+ var u string
1100+ if len (lines ) > 0 {
1101+ u = lines [0 ]
11161102 }
1117- return "" , lines . Err ()
1103+ return u , err
11181104 }()
11191105 if err != nil {
1120- p .badSecurity .error ("Error while reading security.txt: %v" , err )
1121- return errContinue
1106+ return fmt .Sprintf ("Error while reading security.txt: %v" , err )
11221107 }
11231108 if u == "" {
1124- p .badSecurity .error ("No CSAF line found in security.txt." )
1125- return errContinue
1109+ return "No CSAF line found in security.txt."
11261110 }
11271111
11281112 // Try to load
11291113 up , err := url .Parse (u )
11301114 if err != nil {
1131- p .badSecurity .error ("CSAF URL '%s' invalid: %v" , u , err )
1132- return errContinue
1115+ return fmt .Sprintf ("CSAF URL '%s' invalid: %v" , u , err )
11331116 }
11341117
11351118 base , err := url .Parse ("https://" + domain + "/.well-known/" )
11361119 if err != nil {
1137- return err
1120+ return err . Error ()
11381121 }
11391122
11401123 u = base .ResolveReference (up ).String ()
11411124 p .checkTLS (u )
11421125 if res , err = client .Get (u ); err != nil {
1143- p .badSecurity .error ("Cannot fetch %s from security.txt: %v" , u , err )
1144- return errContinue
1126+ return fmt .Sprintf ("Cannot fetch %s from security.txt: %v" , u , err )
11451127 }
11461128 if res .StatusCode != http .StatusOK {
1147- p . badSecurity . error ("Fetching %s failed. Status code %d (%s)" ,
1129+ return fmt . Sprintf ("Fetching %s failed. Status code %d (%s)" ,
11481130 u , res .StatusCode , res .Status )
1149- return errContinue
11501131 }
11511132 defer res .Body .Close ()
11521133 // Compare checksums to already read provider-metadata.json.
11531134 h := sha256 .New ()
11541135 if _ , err := io .Copy (h , res .Body ); err != nil {
1155- p .badSecurity .error ("Reading %s failed: %v" , u , err )
1156- return errContinue
1136+ return fmt .Sprintf ("Reading %s failed: %v" , u , err )
11571137 }
11581138
11591139 if ! bytes .Equal (h .Sum (nil ), p .pmd256 ) {
1160- p . badSecurity . error ("Content of %s from security.txt is not " +
1140+ return fmt . Sprintf ("Content of %s from security.txt is not " +
11611141 "identical to .well-known/csaf/provider-metadata.json" , u )
11621142 }
1143+ return ""
1144+ }
1145+
1146+ // checkDNS checks if the "csaf.data.security.domain.tld" DNS record is available
1147+ // and serves the "provider-metadata.json".
1148+ // It returns an empty string if all checks are passed, otherwise the errormessage.
1149+ func (p * processor ) checkDNS (domain string ) string {
1150+
1151+ client := p .httpClient ()
1152+ path := "https://csaf.data.security." + domain
1153+ res , err := client .Get (path )
1154+ if err != nil {
1155+ return fmt .Sprintf ("Fetching %s failed: %v" , path , err )
1156+ }
1157+ if res .StatusCode != http .StatusOK {
1158+ return fmt .Sprintf ("Fetching %s failed. Status code %d (%s)" ,
1159+ path , res .StatusCode , res .Status )
1160+
1161+ }
1162+ hash := sha256 .New ()
1163+ defer res .Body .Close ()
1164+ content , err := io .ReadAll (res .Body )
1165+ if err != nil {
1166+ return fmt .Sprintf ("Error while reading the response from %s" , path )
1167+ }
1168+ hash .Write (content )
1169+ if ! bytes .Equal (hash .Sum (nil ), p .pmd256 ) {
1170+ return fmt .Sprintf ("%s does not serve the same provider-metadata.json as previously found" , path )
1171+ }
1172+ return ""
1173+ }
1174+
1175+ // checkWellknownMetadataReporter checks if the provider-metadata.json file is
1176+ // available under the /.well-known/csaf/ directory. Returns the errormessage if
1177+ // an error was encountered, or an empty string otherwise
1178+ func (p * processor ) checkWellknown (domain string ) string {
1179+
1180+ client := p .httpClient ()
1181+ path := "https://" + domain + "/.well-known/csaf/provider-metadata.json"
1182+
1183+ res , err := client .Get (path )
1184+ if err != nil {
1185+ return fmt .Sprintf ("Fetching %s failed: %v" , path , err )
1186+ }
1187+ if res .StatusCode != http .StatusOK {
1188+ return fmt .Sprintf ("Fetching %s failed. Status code %d (%s)" ,
1189+ path , res .StatusCode , res .Status )
1190+ }
1191+ return ""
1192+ }
1193+
1194+ // checkWellknownSecurityDNS
1195+ // 1. checks if the provider-metadata.json file is
1196+ // available under the /.well-known/csaf/ directory.
1197+ // 2. Then it checks the security.txt file by making HTTP request to fetch it.
1198+ // 3. After that it checks the existence of the CSAF field in the file
1199+ // content and tries to fetch the value of this field.
1200+ // 4. Finally it checks if the "csaf.data.security.domain.tld" DNS record
1201+ // is available and serves the "provider-metadata.json".
1202+ ///
1203+ // If all three checks fail, errors are given,
1204+ // otherwise warnings for all failed checks.
1205+ // The function returns nil, unless errors outside the checks were found.
1206+ // In that case, errors are returned.
1207+ func (p * processor ) checkWellknownSecurityDNS (domain string ) error {
1208+
1209+ warningsW := p .checkWellknown (domain )
1210+ warningsS := p .checkSecurity (domain )
1211+ warningsD := p .checkDNS (domain )
1212+
1213+ p .badWellknownMetadata .use ()
1214+ p .badSecurity .use ()
1215+ p .badDNSPath .use ()
1216+
1217+ var kind MessageType
1218+ if warningsS == "" || warningsD == "" || warningsW == "" {
1219+ kind = WarnType
1220+ } else {
1221+ kind = ErrorType
1222+ }
11631223
1224+ if warningsW != "" {
1225+ p .badWellknownMetadata .add (kind , warningsW )
1226+ }
1227+ if warningsS != "" {
1228+ p .badSecurity .add (kind , warningsS )
1229+ }
1230+ if warningsD != "" {
1231+ p .badDNSPath .add (kind , warningsD )
1232+ }
11641233 return nil
11651234}
11661235
@@ -1251,64 +1320,3 @@ func (p *processor) checkPGPKeys(domain string) error {
12511320 }
12521321 return nil
12531322}
1254-
1255- // checkWellknownMetadataReporter checks if the provider-metadata.json file is
1256- // available under the /.well-known/csaf/ directory.
1257- // It returns nil if all checks are passed, otherwise error.
1258- func (p * processor ) checkWellknownMetadataReporter (domain string ) error {
1259-
1260- client := p .httpClient ()
1261-
1262- p .badWellknownMetadata .use ()
1263-
1264- path := "https://" + domain + "/.well-known/csaf/provider-metadata.json"
1265-
1266- res , err := client .Get (path )
1267- if err != nil {
1268- p .badWellknownMetadata .error ("Fetching %s failed: %v" , path , err )
1269- return errContinue
1270- }
1271- if res .StatusCode != http .StatusOK {
1272- p .badWellknownMetadata .error ("Fetching %s failed. Status code %d (%s)" ,
1273- path , res .StatusCode , res .Status )
1274- return errContinue
1275- }
1276-
1277- return nil
1278- }
1279-
1280- // checkDNSPathReporter checks if the "csaf.data.security.domain.tld" DNS record is available
1281- // and serves the "provider-metadata.json".
1282- // It returns nil if all checks are passed, otherwise error.
1283- func (p * processor ) checkDNSPathReporter (domain string ) error {
1284-
1285- client := p .httpClient ()
1286-
1287- p .badDNSPath .use ()
1288-
1289- path := "https://csaf.data.security." + domain
1290- res , err := client .Get (path )
1291- if err != nil {
1292- p .badDNSPath .error ("Fetching %s failed: %v" , path , err )
1293- return errContinue
1294- }
1295- if res .StatusCode != http .StatusOK {
1296- p .badDNSPath .error ("Fetching %s failed. Status code %d (%s)" ,
1297- path , res .StatusCode , res .Status )
1298- return errContinue
1299- }
1300- hash := sha256 .New ()
1301- defer res .Body .Close ()
1302- content , err := io .ReadAll (res .Body )
1303- if err != nil {
1304- p .badDNSPath .error ("Error while reading the response from %s" , path )
1305- return errContinue
1306- }
1307- hash .Write (content )
1308- if ! bytes .Equal (hash .Sum (nil ), p .pmd256 ) {
1309- p .badDNSPath .error ("%s does not serve the same provider-metadata.json as previously found" , path )
1310- return errContinue
1311- }
1312-
1313- return nil
1314- }
0 commit comments