diff --git a/cmd/csaf_aggregator/mirror.go b/cmd/csaf_aggregator/mirror.go index a6ef984..a17a180 100644 --- a/cmd/csaf_aggregator/mirror.go +++ b/cmd/csaf_aggregator/mirror.go @@ -557,6 +557,11 @@ func (w *worker) mirrorFiles(tlpLabel csaf.TLPLabel, files []csaf.AdvisoryFile) continue } + if util.CleanFileName(sum.ID) != filename { + log.Printf("ID %q does not match filename %s", + sum.ID, filename) + } + if err := w.extractCategories(label, advisory); err != nil { log.Printf("error: %s: %v\n", file, err) continue diff --git a/cmd/csaf_checker/processor.go b/cmd/csaf_checker/processor.go index 4124455..0613c33 100644 --- a/cmd/csaf_checker/processor.go +++ b/cmd/csaf_checker/processor.go @@ -512,6 +512,12 @@ func (p *processor) integrity( p.invalidAdvisories.error("CSAF file %s has %d validation errors.", u, len(errors)) } + if err := util.IDMatchesFilename(p.expr, doc, filepath.Base(u)); err != nil { + p.invalidAdvisories.error("%s: %v\n", u, err) + continue + + } + // Validate against remote validator. if p.validator != nil { if rvr, err := p.validator.Validate(doc); err != nil { diff --git a/cmd/csaf_downloader/downloader.go b/cmd/csaf_downloader/downloader.go index 36091f5..1e8b62e 100644 --- a/cmd/csaf_downloader/downloader.go +++ b/cmd/csaf_downloader/downloader.go @@ -439,6 +439,11 @@ nextAdvisory: continue } + if err := util.IDMatchesFilename(d.eval, doc, filename); err != nil { + log.Printf("Ignoring %s: %s.\n", file.URL(), err) + continue + } + // Validate against remote validator if d.validator != nil { rvr, err := d.validator.Validate(doc) diff --git a/cmd/csaf_provider/actions.go b/cmd/csaf_provider/actions.go index 83101d0..084f52f 100644 --- a/cmd/csaf_provider/actions.go +++ b/cmd/csaf_provider/actions.go @@ -196,6 +196,11 @@ func (c *controller) upload(r *http.Request) (any, error) { return nil, err } + if util.CleanFileName(ex.ID) != newCSAF { + return nil, fmt.Errorf("ID %q does not match filename %s", + ex.ID, newCSAF) + } + // Check if we have to search for dynamic categories. var dynamicCategories []string if catExprs := c.cfg.DynamicCategories(); len(catExprs) > 0 { diff --git a/cmd/csaf_uploader/main.go b/cmd/csaf_uploader/main.go index 6ac5027..0b7fe56 100644 --- a/cmd/csaf_uploader/main.go +++ b/cmd/csaf_uploader/main.go @@ -243,6 +243,11 @@ func (p *processor) uploadRequest(filename string) (*http.Request, error) { writeStrings("Errors:", errs) return nil, errors.New("local schema check failed") } + + eval := util.NewPathEval() + if err := util.IDMatchesFilename(eval, doc, filepath.Base(filename)); err != nil { + return nil, err + } } body := new(bytes.Buffer) diff --git a/cmd/csaf_validator/main.go b/cmd/csaf_validator/main.go index 78708a5..412200a 100644 --- a/cmd/csaf_validator/main.go +++ b/cmd/csaf_validator/main.go @@ -54,6 +54,7 @@ func main() { func run(opts *options, files []string) error { var validator csaf.RemoteValidator + eval := util.NewPathEval() if opts.RemoteValidator != "" { validatorOptions := csaf.RemoteValidatorOptions{ @@ -109,6 +110,13 @@ func run(opts *options, files []string) error { } else { fmt.Printf("%q passes the schema validation.\n", file) } + + // Check filename agains ID + if err := util.IDMatchesFilename(eval, doc, filepath.Base(file)); err != nil { + log.Printf("%s: %s.\n", file, err) + continue + } + // Validate against remote validator. if validator != nil { rvr, err := validator.Validate(doc) diff --git a/util/file.go b/util/file.go index b4f44cf..266d720 100644 --- a/util/file.go +++ b/util/file.go @@ -9,6 +9,7 @@ package util import ( + "fmt" "io" "math/rand" "os" @@ -38,6 +39,23 @@ func ConformingFileName(fname string) bool { return fname == CleanFileName(fname) } +// IDMatchesFilename checks that filename can be derived from the value +// of document/tracking/id extracted from doc using eval. +// https://docs.oasis-open.org/csaf/csaf/v2.0/os/csaf-v2.0-os.html#51-filename +func IDMatchesFilename(eval *PathEval, doc any, filename string) error { + var id string + if err := eval.Extract(`$.document.tracking.id`, StringMatcher(&id), false, doc); err != nil { + return fmt.Errorf("check that ID matches filename: %v", err) + } + + if CleanFileName(id) != filename { + return fmt.Errorf("document/tracking/id %q does not match filename %s", + id, filename) + } + + return nil +} + // PathExists returns true if path exits. func PathExists(path string) (bool, error) { _, err := os.Stat(path)