Skip to content

Commit

Permalink
Merge branch 'csaf-poc:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
JanHoefelmeyer authored Dec 6, 2023
2 parents c98ec1e + 03e4181 commit 41214a5
Show file tree
Hide file tree
Showing 23 changed files with 390 additions and 219 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Download the binaries from the most recent release assets on Github.

### Build from sources

- A recent version of **Go** (1.21+) should be installed. [Go installation](https://go.dev/doc/install)
- A recent version of **Go** (1.20+) should be installed. [Go installation](https://go.dev/doc/install)

- Clone the repository `git clone https://github.com/csaf-poc/csaf_distribution.git `

Expand Down
58 changes: 44 additions & 14 deletions cmd/csaf_checker/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import (
"golang.org/x/time/rate"

"github.com/csaf-poc/csaf_distribution/v3/csaf"
"github.com/csaf-poc/csaf_distribution/v3/internal/models"
"github.com/csaf-poc/csaf_distribution/v3/util"
)

Expand Down Expand Up @@ -548,7 +547,7 @@ func (p *processor) rolieFeedEntries(feed string) ([]csaf.AdvisoryFile, error) {

// Filter if we have date checking.
if accept := p.cfg.Range; accept != nil {
if pub := time.Time(entry.Published); !pub.IsZero() && !accept.Contains(pub) {
if t := time.Time(entry.Updated); !t.IsZero() && !accept.Contains(t) {
return
}
}
Expand Down Expand Up @@ -667,11 +666,6 @@ func (p *processor) integrity(
var folderYear *int
if m := yearFromURL.FindStringSubmatch(u); m != nil {
year, _ := strconv.Atoi(m[1])
// Check if the year is in the accepted time interval.
if accept := p.cfg.Range; accept != nil &&
!accept.Intersects(models.Year(year)) {
continue
}
folderYear = &year
}

Expand Down Expand Up @@ -1262,10 +1256,26 @@ func (p *processor) checkProviderMetadata(domain string) bool {
// It checks the existence of the CSAF field in the file content and tries to fetch
// the value of this field. Returns an empty string if no error was encountered,
// the errormessage otherwise.
func (p *processor) checkSecurity(domain string) string {
func (p *processor) checkSecurity(domain string, legacy bool) (int, string) {
folder := "https://" + domain + "/"
if !legacy {
folder = folder + ".well-known/"
}
msg := p.checkSecurityFolder(folder)
if msg == "" {
if !legacy {
return 0, "Found valid security.txt within the well-known directory"
}
return 2, "Found valid security.txt in the legacy location"
}
return 1, folder + "security.txt: " + msg
}

// checkSecurityFolder checks the security.txt in a given folder.
func (p *processor) checkSecurityFolder(folder string) string {

client := p.httpClient()
path := "https://" + domain + "/.well-known/security.txt"
path := folder + "security.txt"
res, err := client.Get(path)
if err != nil {
return fmt.Sprintf("Fetching %s failed: %v", path, err)
Expand Down Expand Up @@ -1298,7 +1308,7 @@ func (p *processor) checkSecurity(domain string) string {
return fmt.Sprintf("CSAF URL '%s' invalid: %v", u, err)
}

base, err := url.Parse("https://" + domain + "/.well-known/")
base, err := url.Parse(folder)
if err != nil {
return err.Error()
}
Expand Down Expand Up @@ -1391,25 +1401,45 @@ func (p *processor) checkWellknown(domain string) string {
func (p *processor) checkWellknownSecurityDNS(domain string) error {

warningsW := p.checkWellknown(domain)
warningsS := p.checkSecurity(domain)
// Security check for well known (default) and legacy location
warningsS, sDMessage := p.checkSecurity(domain, false)
// if the security.txt under .well-known was not okay
// check for a security.txt within its legacy location
sLMessage := ""
if warningsS == 1 {
warningsS, sLMessage = p.checkSecurity(domain, true)
}
warningsD := p.checkDNS(domain)

p.badWellknownMetadata.use()
p.badSecurity.use()
p.badDNSPath.use()

var kind MessageType
if warningsS == "" || warningsD == "" || warningsW == "" {
if warningsS != 1 || warningsD == "" || warningsW == "" {
kind = WarnType
} else {
kind = ErrorType
}

// Info, Warning or Error depending on kind and warningS
kindSD := kind
if warningsS == 0 {
kindSD = InfoType
}
kindSL := kind
if warningsS == 2 {
kindSL = InfoType
}

if warningsW != "" {
p.badWellknownMetadata.add(kind, warningsW)
}
if warningsS != "" {
p.badSecurity.add(kind, warningsS)
p.badSecurity.add(kindSD, sDMessage)
// only if the well-known security.txt was not successful:
// report about the legacy location
if warningsS != 0 {
p.badSecurity.add(kindSL, sLMessage)
}
if warningsD != "" {
p.badDNSPath.add(kind, warningsD)
Expand Down
4 changes: 0 additions & 4 deletions cmd/csaf_checker/reporters.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,10 +251,6 @@ func (r *securityReporter) report(p *processor, domain *Domain) {
req.message(WarnType, "Performed no in-depth test of security.txt.")
return
}
if len(p.badSecurity) == 0 {
req.message(InfoType, "Found CSAF entry in security.txt.")
return
}
req.Messages = p.badSecurity
}

Expand Down
3 changes: 2 additions & 1 deletion cmd/csaf_downloader/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import (
"fmt"
"io"
"log"
"log/slog"
"net/http"
"os"
"path/filepath"
"time"

"golang.org/x/exp/slog"

"github.com/csaf-poc/csaf_distribution/v3/internal/certs"
"github.com/csaf-poc/csaf_distribution/v3/internal/filter"
"github.com/csaf-poc/csaf_distribution/v3/internal/models"
Expand Down
3 changes: 2 additions & 1 deletion cmd/csaf_downloader/downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"fmt"
"hash"
"io"
"log/slog"
"net/http"
"net/url"
"os"
Expand All @@ -30,6 +29,8 @@ import (
"sync"
"time"

"golang.org/x/exp/slog"

"github.com/ProtonMail/gopenpgp/v2/crypto"
"golang.org/x/time/rate"

Expand Down
8 changes: 6 additions & 2 deletions cmd/csaf_downloader/forwarder.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ import (
"bytes"
"crypto/tls"
"io"
"log/slog"
"mime/multipart"
"net/http"
"os"
"path/filepath"
"strings"

"golang.org/x/exp/slog"

"github.com/csaf-poc/csaf_distribution/v3/internal/misc"
"github.com/csaf-poc/csaf_distribution/v3/util"
)
Expand Down Expand Up @@ -57,7 +58,10 @@ type forwarder struct {

// newForwarder creates a new forwarder.
func newForwarder(cfg *config) *forwarder {
queue := max(1, cfg.ForwardQueue)
queue := cfg.ForwardQueue
if queue < 1 {
queue = 1
}
return &forwarder{
cfg: cfg,
cmds: make(chan func(*forwarder), queue),
Expand Down
3 changes: 2 additions & 1 deletion cmd/csaf_downloader/forwarder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"encoding/json"
"errors"
"io"
"log/slog"
"mime"
"mime/multipart"
"net/http"
Expand All @@ -23,6 +22,8 @@ import (
"strings"
"testing"

"golang.org/x/exp/slog"

"github.com/csaf-poc/csaf_distribution/v3/internal/options"
"github.com/csaf-poc/csaf_distribution/v3/util"
)
Expand Down
3 changes: 2 additions & 1 deletion cmd/csaf_downloader/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ package main

import (
"context"
"log/slog"
"os"
"os/signal"

"golang.org/x/exp/slog"

"github.com/csaf-poc/csaf_distribution/v3/internal/options"
)

Expand Down
2 changes: 1 addition & 1 deletion cmd/csaf_downloader/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

package main

import "log/slog"
import "golang.org/x/exp/slog"

// stats contains counters of the downloads.
type stats struct {
Expand Down
3 changes: 2 additions & 1 deletion cmd/csaf_downloader/stats_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ package main
import (
"bytes"
"encoding/json"
"log/slog"
"testing"

"golang.org/x/exp/slog"
)

func TestStatsAdd(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion csaf/advisories.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ func (afp *AdvisoryFileProcessor) processROLIE(

// Filter if we have date checking.
if afp.AgeAccept != nil {
if pub := time.Time(entry.Published); !pub.IsZero() && !afp.AgeAccept(pub) {
if t := time.Time(entry.Updated); !t.IsZero() && !afp.AgeAccept(t) {
return
}
}
Expand Down
4 changes: 2 additions & 2 deletions csaf/generate_cvss_enums.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
"go/format"
"log"
"os"
"slices"
"sort"
"strings"
"text/template"
)
Expand Down Expand Up @@ -135,7 +135,7 @@ func main() {
defs = append(defs, k)
}
}
slices.Sort(defs)
sort.Strings(defs)

var source bytes.Buffer

Expand Down
96 changes: 51 additions & 45 deletions csaf/providermetaloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,7 @@ func (pmdl *ProviderMetadataLoader) Load(domain string) *LoadedProviderMetadata
}

// Next load the PMDs from security.txt
secURL := "https://" + domain + "/.well-known/security.txt"
secResults := pmdl.loadFromSecurity(secURL)
secResults := pmdl.loadFromSecurity(domain)

// Filter out the results which are valid.
var secGoods []*LoadedProviderMetadata
Expand Down Expand Up @@ -199,56 +198,63 @@ func (pmdl *ProviderMetadataLoader) Load(domain string) *LoadedProviderMetadata
}

// loadFromSecurity loads the PMDs mentioned in the security.txt.
func (pmdl *ProviderMetadataLoader) loadFromSecurity(path string) []*LoadedProviderMetadata {

res, err := pmdl.client.Get(path)
if err != nil {
pmdl.messages.Add(
HTTPFailed,
fmt.Sprintf("Fetching %q failed: %v", path, err))
return nil
}
if res.StatusCode != http.StatusOK {
pmdl.messages.Add(
HTTPFailed,
fmt.Sprintf("Fetching %q failed: %s (%d)", path, res.Status, res.StatusCode))
return nil
}

// Extract all potential URLs from CSAF.
urls, err := func() ([]string, error) {
defer res.Body.Close()
return ExtractProviderURL(res.Body, true)
}()

if err != nil {
pmdl.messages.Add(
HTTPFailed,
fmt.Sprintf("Loading %q failed: %v", path, err))
return nil
}
func (pmdl *ProviderMetadataLoader) loadFromSecurity(domain string) []*LoadedProviderMetadata {

// If .well-known fails try legacy location.
for _, path := range []string{
"https://" + domain + "/.well-known/security.txt",
"https://" + domain + "/security.txt",
} {
res, err := pmdl.client.Get(path)
if err != nil {
pmdl.messages.Add(
HTTPFailed,
fmt.Sprintf("Fetching %q failed: %v", path, err))
continue
}
if res.StatusCode != http.StatusOK {
pmdl.messages.Add(
HTTPFailed,
fmt.Sprintf("Fetching %q failed: %s (%d)", path, res.Status, res.StatusCode))
continue
}

var loaded []*LoadedProviderMetadata
// Extract all potential URLs from CSAF.
urls, err := func() ([]string, error) {
defer res.Body.Close()
return ExtractProviderURL(res.Body, true)
}()

// Load the URLs
nextURL:
for _, url := range urls {
lpmd := pmdl.loadFromURL(url)
// If loading failed note it down.
if !lpmd.Valid() {
pmdl.messages.AppendUnique(lpmd.Messages)
if err != nil {
pmdl.messages.Add(
HTTPFailed,
fmt.Sprintf("Loading %q failed: %v", path, err))
continue
}
// Check for duplicates
for _, l := range loaded {
if l == lpmd {
continue nextURL

var loaded []*LoadedProviderMetadata

// Load the URLs
nextURL:
for _, url := range urls {
lpmd := pmdl.loadFromURL(url)
// If loading failed note it down.
if !lpmd.Valid() {
pmdl.messages.AppendUnique(lpmd.Messages)
continue
}
// Check for duplicates
for _, l := range loaded {
if l == lpmd {
continue nextURL
}
}
loaded = append(loaded, lpmd)
}
loaded = append(loaded, lpmd)
}

return loaded
return loaded
}
return nil
}

// loadFromURL loads a provider metadata from a given URL.
Expand Down
Loading

0 comments on commit 41214a5

Please sign in to comment.