1
0
Fork 0
mirror of https://github.com/gocsaf/csaf.git synced 2025-12-22 18:15:42 +01:00

Compare commits

..

No commits in common. "main" and "v3.2.0" have entirely different histories.
main ... v3.2.0

56 changed files with 575 additions and 1399 deletions

View file

@ -13,8 +13,8 @@ jobs:
auto-update-readme: auto-update-readme:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v2
- name: Markdown autodocs - name: Markdown autodocs
uses: dineshsonachalam/markdown-autodocs@v1.0.7 uses: dineshsonachalam/markdown-autodocs@v1.0.4
with: with:
output_file_paths: '[./README.md, ./docs/*.md]' output_file_paths: '[./README.md, ./docs/*.md]'

View file

@ -12,11 +12,10 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v6 uses: actions/setup-go@v4
with: with:
go-version: "stable" go-version: "stable"
@ -27,36 +26,15 @@ jobs:
run: go vet ./... run: go vet ./...
- name: gofmt - name: gofmt
uses: Jerome1337/gofmt-action@v1.0.5 uses: Jerome1337/gofmt-action@v1.0.4
with: with:
gofmt-flags: "-l -d" gofmt-flags: "-l -d"
- name: golint
uses: Jerome1337/golint-action@v1.0.3
- name: Revive Action - name: Revive Action
uses: morphy2k/revive-action@v2 uses: morphy2k/revive-action@v2.7.4
- name: Tests - name: Tests
run: go test -v ./... run: go test -v ./...
run_modver:
runs-on: ubuntu-latest
needs: build # Only run when build job was successful
if: ${{ github.event_name == 'pull_request' && success() }}
permissions:
contents: read # Modver needs to read the repo content
pull-requests: write # Modver needs to write comments/status on PRs
steps:
- name: Checkout
uses: actions/checkout@v5
with:
fetch-depth: 0 # Modver needs full history for comparison
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: "stable"
- name: Modver
uses: bobg/modver@v2.12.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
pull_request_url: https://github.com/${{ github.repository }}/pull/${{ github.event.number }}

View file

@ -1,4 +1,4 @@
name: Go Test (oldstable) name: Go
on: on:
push: push:
@ -12,10 +12,10 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v6 uses: actions/setup-go@v4
with: with:
go-version: 'oldstable' go-version: 'oldstable'

View file

@ -5,19 +5,19 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout
uses: actions/checkout@v5
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v6 uses: actions/setup-go@v5
with: with:
go-version-file: "go.mod" go-version: '^1.23.6'
check-latest: true
- name: Set up Node.js - name: Set up Node.js
uses: actions/setup-node@v6 uses: actions/setup-node@v3
with: with:
node-version: 24 node-version: 16
- name: Checkout
uses: actions/checkout@v4
- name: Execute the scripts - name: Execute the scripts
run: | run: |
@ -38,8 +38,8 @@ jobs:
- name: Upload test results - name: Upload test results
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: checker-results name: checker-results
path: | path: |
~/checker-results.html ~/checker-results.html
~/checker-results-no-clientcert.json ~/checker-results-no-clientcert.json
if-no-files-found: error if-no-files-found: error

View file

@ -7,19 +7,17 @@ on:
jobs: jobs:
releases-matrix: releases-matrix:
name: Release Go binaries name: Release Go binaries
# use oldest available ubuntu to be compatible with more libc.so revs.
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
permissions: permissions:
contents: write contents: write
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v5 uses: actions/checkout@v4
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v6 uses: actions/setup-go@v5
with: with:
go-version: '^1.24.9' go-version: '^1.23.6'
check-latest: true
- name: Build - name: Build
run: make dist run: make dist

View file

@ -12,15 +12,15 @@ SHELL = /bin/bash
BUILD = go build BUILD = go build
MKDIR = mkdir -p MKDIR = mkdir -p
.PHONY: build build_linux build_linux_arm64 build_win build_win_arm64 build_mac_amd64 build_mac_arm64 tag_checked_out mostlyclean .PHONY: build build_linux build_win build_mac_amd64 build_mac_arm64 tag_checked_out mostlyclean
all: all:
@echo choose a target from: build build_linux build_linux_arm64 build_win build_win_arm64 build_mac_amd64 build_mac_arm64 mostlyclean @echo choose a target from: build build_linux build_win build_mac_amd64 build_mac_arm64 mostlyclean
@echo prepend \`make BUILDTAG=1\` to checkout the highest git tag before building @echo prepend \`make BUILDTAG=1\` to checkout the highest git tag before building
@echo or set BUILDTAG to a specific tag @echo or set BUILDTAG to a specific tag
# Build all binaries # Build all binaries
build: build_linux build_linux_arm64 build_win build_win_arm64 build_mac_amd64 build_mac_arm64 build: build_linux build_win build_mac_amd64 build_mac_arm64
# if BUILDTAG == 1 set it to the highest git tag # if BUILDTAG == 1 set it to the highest git tag
ifeq ($(strip $(BUILDTAG)),1) ifeq ($(strip $(BUILDTAG)),1)
@ -29,7 +29,7 @@ endif
ifdef BUILDTAG ifdef BUILDTAG
# add the git tag checkout to the requirements of our build targets # add the git tag checkout to the requirements of our build targets
build_linux build_linux_arm64 build_win build_win_arm64 build_mac_amd64 build_mac_arm64: tag_checked_out build_linux build_win build_mac_amd64 build_mac_arm64: tag_checked_out
endif endif
tag_checked_out: tag_checked_out:
@ -47,18 +47,13 @@ tag_checked_out:
# In this case we might in some situations see an error like # In this case we might in some situations see an error like
# `/bin/bash: line 1: 2b55bbb: value too great for base (error token is "2b55bbb")` # `/bin/bash: line 1: 2b55bbb: value too great for base (error token is "2b55bbb")`
# which can be ignored. # which can be ignored.
GITDESC := $(shell git describe --tags --always --dirty=-modified 2>/dev/null || true) GITDESC := $(shell git describe --tags --always)
CURRENT_FOLDER_NAME := $(notdir $(CURDIR))
ifeq ($(strip $(GITDESC)),)
SEMVER := $(CURRENT_FOLDER_NAME)
else
GITDESCPATCH := $(shell echo '$(GITDESC)' | sed -E 's/v?[0-9]+\.[0-9]+\.([0-9]+)[-+]?.*/\1/') GITDESCPATCH := $(shell echo '$(GITDESC)' | sed -E 's/v?[0-9]+\.[0-9]+\.([0-9]+)[-+]?.*/\1/')
SEMVERPATCH := $(shell echo $$(( $(GITDESCPATCH) + 1 ))) SEMVERPATCH := $(shell echo $$(( $(GITDESCPATCH) + 1 )))
# Hint: The second regexp in the next line only matches # Hint: The second regexp in the next line only matches
# if there is a hyphen (`-`) followed by a number, # if there is a hyphen (`-`) followed by a number,
# by which we assume that git describe has added a string after the tag # by which we assume that git describe has added a string after the tag
SEMVER := $(shell echo '$(GITDESC)' | sed -E -e 's/^v//' -e 's/([0-9]+\.[0-9]+\.)([0-9]+)(-[1-9].*)/\1$(SEMVERPATCH)\3/' ) SEMVER := $(shell echo '$(GITDESC)' | sed -E -e 's/^v//' -e 's/([0-9]+\.[0-9]+\.)([0-9]+)(-[1-9].*)/\1$(SEMVERPATCH)\3/' )
endif
testsemver: testsemver:
@echo from \'$(GITDESC)\' transformed to \'$(SEMVER)\' @echo from \'$(GITDESC)\' transformed to \'$(SEMVER)\'
@ -69,49 +64,31 @@ LDFLAGS = -ldflags "-X github.com/gocsaf/csaf/v3/util.SemVersion=$(SEMVER)"
# Build binaries and place them under bin-$(GOOS)-$(GOARCH) # Build binaries and place them under bin-$(GOOS)-$(GOARCH)
# Using 'Target-specific Variable Values' to specify the build target system # Using 'Target-specific Variable Values' to specify the build target system
build_linux: GOOS=linux GOARCH = amd64
build_linux: GOARCH=amd64 build_linux: GOOS = linux
build_win: GOOS = windows
build_mac_amd64: GOOS = darwin
build_win: GOOS=windows build_mac_arm64: GOARCH = arm64
build_win: GOARCH=amd64 build_mac_arm64: GOOS = darwin
build_mac_amd64: GOOS=darwin build_linux build_win build_mac_amd64 build_mac_arm64:
build_mac_amd64: GOARCH=amd64
build_mac_arm64: GOOS=darwin
build_mac_arm64: GOARCH=arm64
build_linux_arm64: GOOS=linux
build_linux_arm64: GOARCH=arm64
build_win_arm64: GOOS=windows
build_win_arm64: GOARCH=arm64
build_linux build_linux_arm64 build_win build_win_arm64 build_mac_amd64 build_mac_arm64:
$(eval BINDIR = bin-$(GOOS)-$(GOARCH)/ ) $(eval BINDIR = bin-$(GOOS)-$(GOARCH)/ )
$(MKDIR) $(BINDIR) $(MKDIR) $(BINDIR)
env GOARCH=$(GOARCH) GOOS=$(GOOS) $(BUILD) -o $(BINDIR) $(LDFLAGS) -v ./cmd/... env GOARCH=$(GOARCH) GOOS=$(GOOS) $(BUILD) -o $(BINDIR) $(LDFLAGS) -v ./cmd/...
DISTDIR := csaf-$(SEMVER) DISTDIR := csaf-$(SEMVER)
dist: build_linux build_linux_arm64 build_win build_win_arm64 build_mac_amd64 build_mac_arm64 dist: build_linux build_win build_mac_amd64 build_mac_arm64
mkdir -p dist mkdir -p dist
mkdir -p dist/$(DISTDIR)-windows-amd64/bin-windows-amd64 mkdir -p dist/$(DISTDIR)-windows-amd64/bin-windows-amd64
mkdir -p dist/$(DISTDIR)-windows-arm64/bin-windows-arm64
cp README.md dist/$(DISTDIR)-windows-amd64 cp README.md dist/$(DISTDIR)-windows-amd64
cp README.md dist/$(DISTDIR)-windows-arm64
cp bin-windows-amd64/csaf_uploader.exe bin-windows-amd64/csaf_validator.exe \ cp bin-windows-amd64/csaf_uploader.exe bin-windows-amd64/csaf_validator.exe \
bin-windows-amd64/csaf_checker.exe bin-windows-amd64/csaf_downloader.exe \ bin-windows-amd64/csaf_checker.exe bin-windows-amd64/csaf_downloader.exe \
dist/$(DISTDIR)-windows-amd64/bin-windows-amd64/ dist/$(DISTDIR)-windows-amd64/bin-windows-amd64/
cp bin-windows-arm64/csaf_uploader.exe bin-windows-arm64/csaf_validator.exe \
bin-windows-arm64/csaf_checker.exe bin-windows-arm64/csaf_downloader.exe \
dist/$(DISTDIR)-windows-arm64/bin-windows-arm64/
mkdir -p dist/$(DISTDIR)-windows-amd64/docs mkdir -p dist/$(DISTDIR)-windows-amd64/docs
mkdir -p dist/$(DISTDIR)-windows-arm64/docs
cp docs/csaf_uploader.md docs/csaf_validator.md docs/csaf_checker.md \ cp docs/csaf_uploader.md docs/csaf_validator.md docs/csaf_checker.md \
docs/csaf_downloader.md dist/$(DISTDIR)-windows-amd64/docs docs/csaf_downloader.md dist/$(DISTDIR)-windows-amd64/docs
cp docs/csaf_uploader.md docs/csaf_validator.md docs/csaf_checker.md \
docs/csaf_downloader.md dist/$(DISTDIR)-windows-arm64/docs
mkdir -p dist/$(DISTDIR)-macos/bin-darwin-amd64 \ mkdir -p dist/$(DISTDIR)-macos/bin-darwin-amd64 \
dist/$(DISTDIR)-macos/bin-darwin-arm64 \ dist/$(DISTDIR)-macos/bin-darwin-arm64 \
dist/$(DISTDIR)-macos/docs dist/$(DISTDIR)-macos/docs
@ -121,20 +98,9 @@ dist: build_linux build_linux_arm64 build_win build_win_arm64 build_mac_amd64 bu
cp docs/$${f}.md dist/$(DISTDIR)-macos/docs ; \ cp docs/$${f}.md dist/$(DISTDIR)-macos/docs ; \
done done
mkdir dist/$(DISTDIR)-gnulinux-amd64 mkdir dist/$(DISTDIR)-gnulinux-amd64
mkdir dist/$(DISTDIR)-gnulinux-arm64 cp -r README.md docs bin-linux-amd64 dist/$(DISTDIR)-gnulinux-amd64
cp -r README.md bin-linux-amd64 dist/$(DISTDIR)-gnulinux-amd64
cp -r README.md bin-linux-arm64 dist/$(DISTDIR)-gnulinux-arm64
# adjust which docs to copy
mkdir -p dist/tmp_docs
cp -r docs/examples dist/tmp_docs
cp docs/*.md dist/tmp_docs
cp -r dist/tmp_docs dist/$(DISTDIR)-gnulinux-amd64/docs
cp -r dist/tmp_docs dist/$(DISTDIR)-gnulinux-arm64/docs
rm -rf dist/tmp_docs
cd dist/ ; zip -r $(DISTDIR)-windows-amd64.zip $(DISTDIR)-windows-amd64/ cd dist/ ; zip -r $(DISTDIR)-windows-amd64.zip $(DISTDIR)-windows-amd64/
cd dist/ ; zip -r $(DISTDIR)-windows-arm64.zip $(DISTDIR)-windows-arm64/
cd dist/ ; tar -cvmlzf $(DISTDIR)-gnulinux-amd64.tar.gz $(DISTDIR)-gnulinux-amd64/ cd dist/ ; tar -cvmlzf $(DISTDIR)-gnulinux-amd64.tar.gz $(DISTDIR)-gnulinux-amd64/
cd dist/ ; tar -cvmlzf $(DISTDIR)-gnulinux-arm64.tar.gz $(DISTDIR)-gnulinux-arm64/
cd dist/ ; tar -cvmlzf $(DISTDIR)-macos.tar.gz $(DISTDIR)-macos cd dist/ ; tar -cvmlzf $(DISTDIR)-macos.tar.gz $(DISTDIR)-macos
# Remove bin-*-* and dist directories # Remove bin-*-* and dist directories

View file

@ -9,6 +9,14 @@
--> -->
> [!IMPORTANT]
> To avoid future breakage, if you still use `csaf-poc`:
> 1. Adjust your HTML links.
> 2. Adjust your go module paths, see [#579](https://github.com/gocsaf/csaf/issues/579#issuecomment-2497244379).
>
> (This repository was moved here on 2024-10-28. The old one is deprecated
> and redirection will be switched off a few months later.)
# csaf # csaf
@ -41,20 +49,13 @@ is a tool for testing a CSAF Trusted Provider according to [Section 7 of the CSA
### [csaf_aggregator](docs/csaf_aggregator.md) ### [csaf_aggregator](docs/csaf_aggregator.md)
is a CSAF Aggregator, to list or mirror providers. is a CSAF Aggregator, to list or mirror providers.
## Other stuff
## Use as go library
The modules of this repository can be used as library by other Go applications. [ISDuBA](https://github.com/ISDuBA/ISDuBA) does so, for example.
But there is only limited support and thus it is _not officially supported_.
There are plans to change this without a concrete schedule within a future major release, e.g. see [#367](https://github.com/gocsaf/csaf/issues/367).
Initially envisioned as a toolbox, it was not constructed as a library,
and to name one issue, exposes too many functions.
This leads to problems like [#634](https://github.com/gocsaf/csaf/issues/634), where we have to accept that with 3.2.0 there was an unintended API change.
### [examples](./examples/README.md) ### [examples](./examples/README.md)
are small examples of how to use `github.com/gocsaf/csaf` as an API. Currently this is a work in progress. are small examples of how to use `github.com/gocsaf/csaf`
as an API. Currently this is a work in progress, as usage of this repository
as a library to access is _not officially supported_, e.g.
see https://github.com/gocsaf/csaf/issues/367 .
## Setup ## Setup
Binaries for the server side are only available and tested Binaries for the server side are only available and tested
@ -78,8 +79,7 @@ Download the binaries from the most recent release assets on Github.
### Build from sources ### Build from sources
- Needs a [supported version](docs/Development.md) of **Go** to be installed. - A recent version of **Go** (1.23+) should be installed. [Go installation](https://go.dev/doc/install)
[Go installation](https://go.dev/doc/install)
- Clone the repository `git clone https://github.com/gocsaf/csaf.git ` - Clone the repository `git clone https://github.com/gocsaf/csaf.git `
@ -107,14 +107,6 @@ Binaries will be placed in directories named like `bin-linux-amd64/` and `bin-wi
For further details of the development process consult our [development page](./docs/Development.md). For further details of the development process consult our [development page](./docs/Development.md).
## Previous repo URLs
> [!NOTE]
> To avoid future breakage, if you have `csaf-poc` in some of your URLs:
> 1. Adjust your HTML links.
> 2. Adjust your go module paths, see [#579](https://github.com/gocsaf/csaf/issues/579#issuecomment-2497244379).
>
> (This repository was moved here from https://github.com/csaf-poc/csaf_distribution on 2024-10-28. The old one is deprecated and redirection will be switched off sometime in 2025.)
## License ## License

View file

@ -13,6 +13,7 @@ import (
"crypto/sha256" "crypto/sha256"
"crypto/sha512" "crypto/sha512"
"encoding/csv" "encoding/csv"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -24,7 +25,6 @@ import (
"time" "time"
"github.com/gocsaf/csaf/v3/csaf" "github.com/gocsaf/csaf/v3/csaf"
"github.com/gocsaf/csaf/v3/internal/misc"
"github.com/gocsaf/csaf/v3/util" "github.com/gocsaf/csaf/v3/util"
) )
@ -81,7 +81,7 @@ func (w *worker) checkInterims(
if err := func() error { if err := func() error {
defer res.Body.Close() defer res.Body.Close()
tee := io.TeeReader(res.Body, hasher) tee := io.TeeReader(res.Body, hasher)
return misc.StrictJSONParse(tee, &doc) return json.NewDecoder(tee).Decode(&doc)
}(); err != nil { }(); err != nil {
return nil, err return nil, err
} }

View file

@ -13,6 +13,7 @@ import (
"crypto/sha256" "crypto/sha256"
"crypto/sha512" "crypto/sha512"
"encoding/hex" "encoding/hex"
"encoding/json"
"fmt" "fmt"
"io" "io"
"log/slog" "log/slog"
@ -30,7 +31,6 @@ import (
"github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/ProtonMail/gopenpgp/v2/crypto"
"github.com/gocsaf/csaf/v3/csaf" "github.com/gocsaf/csaf/v3/csaf"
"github.com/gocsaf/csaf/v3/internal/misc"
"github.com/gocsaf/csaf/v3/util" "github.com/gocsaf/csaf/v3/util"
) )
@ -67,7 +67,7 @@ func (w *worker) mirrorInternal() (*csaf.AggregatorCSAFProvider, error) {
// Collecting the categories per label. // Collecting the categories per label.
w.categories = map[string]util.Set[string]{} w.categories = map[string]util.Set[string]{}
pmdURL, err := url.Parse(w.loc) base, err := url.Parse(w.loc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -76,7 +76,7 @@ func (w *worker) mirrorInternal() (*csaf.AggregatorCSAFProvider, error) {
w.client, w.client,
w.expr, w.expr,
w.metadataProvider, w.metadataProvider,
pmdURL) base)
afp.AgeAccept = w.provider.ageAccept(w.processor.cfg) afp.AgeAccept = w.provider.ageAccept(w.processor.cfg)
@ -538,7 +538,7 @@ func (w *worker) mirrorFiles(tlpLabel csaf.TLPLabel, files []csaf.AdvisoryFile)
download := func(r io.Reader) error { download := func(r io.Reader) error {
tee := io.TeeReader(r, hasher) tee := io.TeeReader(r, hasher)
return misc.StrictJSONParse(tee, &advisory) return json.NewDecoder(tee).Decode(&advisory)
} }
if err := downloadJSON(w.client, file.URL(), download); err != nil { if err := downloadJSON(w.client, file.URL(), download); err != nil {
@ -627,6 +627,7 @@ func (w *worker) mirrorFiles(tlpLabel csaf.TLPLabel, files []csaf.AdvisoryFile)
// If this fails it creates a signature itself with the configured key. // If this fails it creates a signature itself with the configured key.
func (w *worker) downloadSignatureOrSign(url, fname string, data []byte) error { func (w *worker) downloadSignatureOrSign(url, fname string, data []byte) error {
sig, err := w.downloadSignature(url) sig, err := w.downloadSignature(url)
if err != nil { if err != nil {
if err != errNotFound { if err != errNotFound {
w.log.Error("Could not find signature URL", "url", url, "err", err) w.log.Error("Could not find signature URL", "url", url, "err", err)

View file

@ -13,8 +13,6 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"github.com/gocsaf/csaf/v3/internal/misc"
"github.com/PuerkitoBio/goquery" "github.com/PuerkitoBio/goquery"
"github.com/gocsaf/csaf/v3/util" "github.com/gocsaf/csaf/v3/util"
@ -95,12 +93,7 @@ func (pgs pages) listed(
return err return err
} }
// Links may be relative // Links may be relative
var abs string abs := baseURL.ResolveReference(u).String()
if u.IsAbs() {
abs = u.String()
} else {
abs = misc.JoinURL(baseURL, u).String()
}
content.links.Add(abs) content.links.Add(abs)
return nil return nil
}) })

View file

@ -15,6 +15,7 @@ import (
"crypto/sha512" "crypto/sha512"
"crypto/tls" "crypto/tls"
"encoding/csv" "encoding/csv"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -28,8 +29,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/gocsaf/csaf/v3/internal/misc"
"github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/ProtonMail/gopenpgp/v2/crypto"
"golang.org/x/time/rate" "golang.org/x/time/rate"
@ -252,14 +251,14 @@ func (p *processor) run(domains []string) (*Report, error) {
p.reset() p.reset()
if !p.checkProviderMetadata(d) { if !p.checkProviderMetadata(d) {
// We need to fail the domain if the PMD cannot be parsed. // We cannot build a report if the provider metadata cannot be parsed.
p.badProviderMetadata.use() log.Printf("Could not parse the Provider-Metadata.json of: %s\n", d)
p.badProviderMetadata.error("Could not parse the Provider-Metadata.json of: %s", d) continue
} }
if err := p.checkDomain(d); err != nil { if err := p.checkDomain(d); err != nil {
p.badProviderMetadata.use() log.Printf("Failed to find valid provider-metadata.json for domain %s: %v. "+
p.badProviderMetadata.error("Failed to find valid provider-metadata.json for domain %s: %v. ", d, err) "Continuing with next domain.", d, err)
continue
} }
domain := &Domain{Name: d} domain := &Domain{Name: d}
@ -270,10 +269,8 @@ func (p *processor) run(domains []string) (*Report, error) {
} }
if domain.Role == nil { if domain.Role == nil {
log.Printf("No role found in meta data for domain %q\n", d) log.Printf("No role found in meta data. Ignoring domain %q\n", d)
// Assume trusted provider to continue report generation continue
role := csaf.MetadataRoleTrustedProvider
domain.Role = &role
} }
rules := roleRequirements(*domain.Role) rules := roleRequirements(*domain.Role)
@ -516,7 +513,7 @@ func (p *processor) rolieFeedEntries(feed string) ([]csaf.AdvisoryFile, error) {
return nil, nil, fmt.Errorf("%s: %v", feed, err) return nil, nil, fmt.Errorf("%s: %v", feed, err)
} }
var rolieDoc any var rolieDoc any
err = misc.StrictJSONParse(bytes.NewReader(all), &rolieDoc) err = json.NewDecoder(bytes.NewReader(all)).Decode(&rolieDoc)
return rfeed, rolieDoc, err return rfeed, rolieDoc, err
}() }()
if err != nil { if err != nil {
@ -534,7 +531,7 @@ func (p *processor) rolieFeedEntries(feed string) ([]csaf.AdvisoryFile, error) {
if len(errors) > 0 { if len(errors) > 0 {
p.badProviderMetadata.error("%s: Validating against JSON schema failed:", feed) p.badProviderMetadata.error("%s: Validating against JSON schema failed:", feed)
for _, msg := range errors { for _, msg := range errors {
p.badProviderMetadata.error("%s", strings.ReplaceAll(msg, `%`, `%%`)) p.badProviderMetadata.error(strings.ReplaceAll(msg, `%`, `%%`))
} }
} }
@ -626,9 +623,15 @@ var yearFromURL = regexp.MustCompile(`.*/(\d{4})/[^/]+$`)
// mistakes, from conforming filenames to invalid advisories. // mistakes, from conforming filenames to invalid advisories.
func (p *processor) integrity( func (p *processor) integrity(
files []csaf.AdvisoryFile, files []csaf.AdvisoryFile,
base string,
mask whereType, mask whereType,
lg func(MessageType, string, ...any), lg func(MessageType, string, ...any),
) error { ) error {
b, err := url.Parse(base)
if err != nil {
return err
}
makeAbs := makeAbsolute(b)
client := p.httpClient() client := p.httpClient()
var data bytes.Buffer var data bytes.Buffer
@ -639,8 +642,9 @@ func (p *processor) integrity(
lg(ErrorType, "Bad URL %s: %v", f, err) lg(ErrorType, "Bad URL %s: %v", f, err)
continue continue
} }
fp = makeAbs(fp)
u := fp.String() u := b.ResolveReference(fp).String()
// Should this URL be ignored? // Should this URL be ignored?
if p.cfg.ignoreURL(u) { if p.cfg.ignoreURL(u) {
@ -695,7 +699,7 @@ func (p *processor) integrity(
if err := func() error { if err := func() error {
defer res.Body.Close() defer res.Body.Close()
tee := io.TeeReader(res.Body, hasher) tee := io.TeeReader(res.Body, hasher)
return misc.StrictJSONParse(tee, &doc) return json.NewDecoder(tee).Decode(&doc)
}(); err != nil { }(); err != nil {
lg(ErrorType, "Reading %s failed: %v", u, err) lg(ErrorType, "Reading %s failed: %v", u, err)
continue continue
@ -734,7 +738,7 @@ func (p *processor) integrity(
switch date, fault := p.extractTime(doc, `initial_release_date`, u); { switch date, fault := p.extractTime(doc, `initial_release_date`, u); {
case fault != "": case fault != "":
p.badFolders.error("%s", fault) p.badFolders.error(fault)
case folderYear == nil: case folderYear == nil:
p.badFolders.error("No year folder found in %s", u) p.badFolders.error("No year folder found in %s", u)
case date.UTC().Year() != *folderYear: case date.UTC().Year() != *folderYear:
@ -742,7 +746,7 @@ func (p *processor) integrity(
} }
current, fault := p.extractTime(doc, `current_release_date`, u) current, fault := p.extractTime(doc, `current_release_date`, u)
if fault != "" { if fault != "" {
p.badChanges.error("%s", fault) p.badChanges.error(fault)
} else { } else {
p.timesAdv[f.URL()] = current p.timesAdv[f.URL()] = current
} }
@ -772,7 +776,8 @@ func (p *processor) integrity(
lg(ErrorType, "Bad URL %s: %v", x.url(), err) lg(ErrorType, "Bad URL %s: %v", x.url(), err)
continue continue
} }
hashFile := hu.String() hu = makeAbs(hu)
hashFile := b.ResolveReference(hu).String()
p.checkTLS(hashFile) p.checkTLS(hashFile)
if res, err = client.Get(hashFile); err != nil { if res, err = client.Get(hashFile); err != nil {
@ -812,7 +817,7 @@ func (p *processor) integrity(
msgType = InfoType msgType = InfoType
} }
for _, fetchError := range hashFetchErrors { for _, fetchError := range hashFetchErrors {
p.badIntegrities.add(msgType, "%s", fetchError) p.badIntegrities.add(msgType, fetchError)
} }
// Check signature // Check signature
@ -821,7 +826,8 @@ func (p *processor) integrity(
lg(ErrorType, "Bad URL %s: %v", f.SignURL(), err) lg(ErrorType, "Bad URL %s: %v", f.SignURL(), err)
continue continue
} }
sigFile := su.String() su = makeAbs(su)
sigFile := b.ResolveReference(su).String()
p.checkTLS(sigFile) p.checkTLS(sigFile)
p.badSignatures.use() p.badSignatures.use()
@ -941,13 +947,12 @@ func (p *processor) checkIndex(base string, mask whereType) error {
scanner := bufio.NewScanner(res.Body) scanner := bufio.NewScanner(res.Body)
for line := 1; scanner.Scan(); line++ { for line := 1; scanner.Scan(); line++ {
u := scanner.Text() u := scanner.Text()
up, err := url.Parse(u) if _, err := url.Parse(u); err != nil {
if err != nil {
p.badIntegrities.error("index.txt contains invalid URL %q in line %d", u, line) p.badIntegrities.error("index.txt contains invalid URL %q in line %d", u, line)
continue continue
} }
files = append(files, csaf.DirectoryAdvisoryFile{Path: misc.JoinURL(bu, up).String()}) files = append(files, csaf.DirectoryAdvisoryFile{Path: u})
} }
return files, scanner.Err() return files, scanner.Err()
}() }()
@ -962,7 +967,7 @@ func (p *processor) checkIndex(base string, mask whereType) error {
// Block rolie checks. // Block rolie checks.
p.labelChecker.feedLabel = "" p.labelChecker.feedLabel = ""
return p.integrity(files, mask, p.badIndices.add) return p.integrity(files, base, mask, p.badIndices.add)
} }
// checkChanges fetches the "changes.csv" and calls the "checkTLS" method for HTTPs checks. // checkChanges fetches the "changes.csv" and calls the "checkTLS" method for HTTPs checks.
@ -1029,13 +1034,9 @@ func (p *processor) checkChanges(base string, mask whereType) error {
} }
path := r[pathColumn] path := r[pathColumn]
pathURL, err := url.Parse(path) times, files =
if err != nil { append(times, t),
return nil, nil, err append(files, csaf.DirectoryAdvisoryFile{Path: path})
}
times, files = append(times, t),
append(files, csaf.DirectoryAdvisoryFile{Path: misc.JoinURL(bu, pathURL).String()})
p.timesChanges[path] = t p.timesChanges[path] = t
} }
return times, files, nil return times, files, nil
@ -1050,7 +1051,7 @@ func (p *processor) checkChanges(base string, mask whereType) error {
if p.cfg.Range != nil { if p.cfg.Range != nil {
filtered = " (maybe filtered out by time interval)" filtered = " (maybe filtered out by time interval)"
} }
p.badChanges.warn("%s", "no entries in changes.csv found"+filtered) p.badChanges.warn("no entries in changes.csv found" + filtered)
} }
if !sort.SliceIsSorted(times, func(i, j int) bool { if !sort.SliceIsSorted(times, func(i, j int) bool {
@ -1062,7 +1063,7 @@ func (p *processor) checkChanges(base string, mask whereType) error {
// Block rolie checks. // Block rolie checks.
p.labelChecker.feedLabel = "" p.labelChecker.feedLabel = ""
return p.integrity(files, mask, p.badChanges.add) return p.integrity(files, base, mask, p.badChanges.add)
} }
// empty checks if list of strings contains at least one none empty string. // empty checks if list of strings contains at least one none empty string.
@ -1298,8 +1299,8 @@ func (p *processor) checkProviderMetadata(domain string) bool {
for i := range lpmd.Messages { for i := range lpmd.Messages {
p.badProviderMetadata.warn( p.badProviderMetadata.warn(
"Unexpected situation while loading provider-metadata.json: %s", "Unexpected situation while loading provider-metadata.json: " +
lpmd.Messages[i].Message) lpmd.Messages[i].Message)
} }
if !lpmd.Valid() { if !lpmd.Valid() {
@ -1363,11 +1364,17 @@ func (p *processor) checkSecurityFolder(folder string) string {
} }
// Try to load // Try to load
_, err = url.Parse(u) up, err := url.Parse(u)
if err != nil { if err != nil {
return fmt.Sprintf("CSAF URL '%s' invalid: %v", u, err) return fmt.Sprintf("CSAF URL '%s' invalid: %v", u, err)
} }
base, err := url.Parse(folder)
if err != nil {
return err.Error()
}
u = base.ResolveReference(up).String()
p.checkTLS(u) p.checkTLS(u)
if res, err = client.Get(u); err != nil { if res, err = client.Get(u); err != nil {
return fmt.Sprintf("Cannot fetch %s from security.txt: %v", u, err) return fmt.Sprintf("Cannot fetch %s from security.txt: %v", u, err)
@ -1399,31 +1406,32 @@ func (p *processor) checkDNS(domain string) {
res, err := client.Get(path) res, err := client.Get(path)
if err != nil { if err != nil {
p.badDNSPath.add(ErrorType, p.badDNSPath.add(ErrorType,
"Fetching %s failed: %v", path, err) fmt.Sprintf("Fetching %s failed: %v", path, err))
return return
} }
if res.StatusCode != http.StatusOK { if res.StatusCode != http.StatusOK {
p.badDNSPath.add(ErrorType, "Fetching %s failed. Status code %d (%s)", p.badDNSPath.add(ErrorType, fmt.Sprintf("Fetching %s failed. Status code %d (%s)",
path, res.StatusCode, res.Status) path, res.StatusCode, res.Status))
} }
hash := sha256.New() hash := sha256.New()
defer res.Body.Close() defer res.Body.Close()
content, err := io.ReadAll(res.Body) content, err := io.ReadAll(res.Body)
if err != nil { if err != nil {
p.badDNSPath.add(ErrorType, p.badDNSPath.add(ErrorType,
"Error while reading the response from %s", path) fmt.Sprintf("Error while reading the response from %s", path))
} }
hash.Write(content) hash.Write(content)
if !bytes.Equal(hash.Sum(nil), p.pmd256) { if !bytes.Equal(hash.Sum(nil), p.pmd256) {
p.badDNSPath.add(ErrorType, p.badDNSPath.add(ErrorType,
"%s does not serve the same provider-metadata.json as previously found", fmt.Sprintf("%s does not serve the same provider-metadata.json as previously found",
path) path))
} }
} }
// checkWellknown checks if the provider-metadata.json file is // checkWellknown checks if the provider-metadata.json file is
// available under the /.well-known/csaf/ directory. // available under the /.well-known/csaf/ directory.
func (p *processor) checkWellknown(domain string) { func (p *processor) checkWellknown(domain string) {
p.badWellknownMetadata.use() p.badWellknownMetadata.use()
client := p.httpClient() client := p.httpClient()
path := "https://" + domain + "/.well-known/csaf/provider-metadata.json" path := "https://" + domain + "/.well-known/csaf/provider-metadata.json"
@ -1431,12 +1439,11 @@ func (p *processor) checkWellknown(domain string) {
res, err := client.Get(path) res, err := client.Get(path)
if err != nil { if err != nil {
p.badWellknownMetadata.add(ErrorType, p.badWellknownMetadata.add(ErrorType,
"Fetching %s failed: %v", path, err) fmt.Sprintf("Fetching %s failed: %v", path, err))
return
} }
if res.StatusCode != http.StatusOK { if res.StatusCode != http.StatusOK {
p.badWellknownMetadata.add(ErrorType, "Fetching %s failed. Status code %d (%s)", p.badWellknownMetadata.add(ErrorType, fmt.Sprintf("Fetching %s failed. Status code %d (%s)",
path, res.StatusCode, res.Status) path, res.StatusCode, res.Status))
} }
} }
@ -1473,13 +1480,13 @@ func (p *processor) checkWellknownSecurityDNS(domain string) error {
// but found in the legacy location, and inform about finding it there (2). // but found in the legacy location, and inform about finding it there (2).
switch warnings { switch warnings {
case 0: case 0:
p.badSecurity.add(InfoType, "%s", sDMessage) p.badSecurity.add(InfoType, sDMessage)
case 1: case 1:
p.badSecurity.add(ErrorType, "%s", sDMessage) p.badSecurity.add(ErrorType, sDMessage)
p.badSecurity.add(ErrorType, "%s", sLMessage) p.badSecurity.add(ErrorType, sLMessage)
case 2: case 2:
p.badSecurity.add(WarnType, "%s", sDMessage) p.badSecurity.add(WarnType, sDMessage)
p.badSecurity.add(InfoType, "%s", sLMessage) p.badSecurity.add(InfoType, sLMessage)
} }
p.checkDNS(domain) p.checkDNS(domain)
@ -1515,6 +1522,11 @@ func (p *processor) checkPGPKeys(_ string) error {
client := p.httpClient() client := p.httpClient()
base, err := url.Parse(p.pmdURL)
if err != nil {
return err
}
for i := range keys { for i := range keys {
key := &keys[i] key := &keys[i]
if key.URL == nil { if key.URL == nil {
@ -1527,11 +1539,10 @@ func (p *processor) checkPGPKeys(_ string) error {
continue continue
} }
// Todo: refactor all methods to directly accept *url.URL u := base.ResolveReference(up).String()
u := up.String()
p.checkTLS(u) p.checkTLS(u)
res, err := client.Get(*key.URL) res, err := client.Get(u)
if err != nil { if err != nil {
p.badPGPs.error("Fetching public OpenPGP key %s failed: %v.", u, err) p.badPGPs.error("Fetching public OpenPGP key %s failed: %v.", u, err)
continue continue

View file

@ -216,6 +216,11 @@ func defaults[T any](p *T, def T) T {
// processROLIEFeeds goes through all ROLIE feeds and checks their // processROLIEFeeds goes through all ROLIE feeds and checks their
// integrity and completeness. // integrity and completeness.
func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error { func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
base, err := url.Parse(p.pmdURL)
if err != nil {
return err
}
p.badROLIEFeed.use() p.badROLIEFeed.use()
advisories := map[*csaf.Feed][]csaf.AdvisoryFile{} advisories := map[*csaf.Feed][]csaf.AdvisoryFile{}
@ -227,11 +232,12 @@ func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
if feed.URL == nil { if feed.URL == nil {
continue continue
} }
feedBase, err := url.Parse(string(*feed.URL)) up, err := url.Parse(string(*feed.URL))
if err != nil { if err != nil {
p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err) p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err)
continue continue
} }
feedBase := base.ResolveReference(up)
feedURL := feedBase.String() feedURL := feedBase.String()
p.checkTLS(feedURL) p.checkTLS(feedURL)
@ -258,12 +264,13 @@ func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
continue continue
} }
feedURL, err := url.Parse(string(*feed.URL)) up, err := url.Parse(string(*feed.URL))
if err != nil { if err != nil {
p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err) p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err)
continue continue
} }
feedURL := base.ResolveReference(up)
feedBase, err := util.BaseURL(feedURL) feedBase, err := util.BaseURL(feedURL)
if err != nil { if err != nil {
p.badProviderMetadata.error("Bad base path: %v", err) p.badProviderMetadata.error("Bad base path: %v", err)
@ -283,7 +290,7 @@ func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
// TODO: Issue a warning if we want check AMBER+ without an // TODO: Issue a warning if we want check AMBER+ without an
// authorizing client. // authorizing client.
if err := p.integrity(files, rolieMask, p.badProviderMetadata.add); err != nil { if err := p.integrity(files, feedBase, rolieMask, p.badProviderMetadata.add); err != nil {
if err != errContinue { if err != errContinue {
return err return err
} }
@ -312,12 +319,13 @@ func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
continue continue
} }
feedBase, err := url.Parse(string(*feed.URL)) up, err := url.Parse(string(*feed.URL))
if err != nil { if err != nil {
p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err) p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err)
continue continue
} }
feedBase := base.ResolveReference(up)
makeAbs := makeAbsolute(feedBase) makeAbs := makeAbsolute(feedBase)
label := defaults(feed.TLPLabel, csaf.TLPLabelUnlabeled) label := defaults(feed.TLPLabel, csaf.TLPLabelUnlabeled)

View file

@ -35,7 +35,6 @@ import (
"golang.org/x/time/rate" "golang.org/x/time/rate"
"github.com/gocsaf/csaf/v3/csaf" "github.com/gocsaf/csaf/v3/csaf"
"github.com/gocsaf/csaf/v3/internal/misc"
"github.com/gocsaf/csaf/v3/util" "github.com/gocsaf/csaf/v3/util"
) )
@ -226,7 +225,7 @@ func (d *downloader) download(ctx context.Context, domain string) error {
} }
} }
pmdURL, err := url.Parse(lpmd.URL) base, err := url.Parse(lpmd.URL)
if err != nil { if err != nil {
return fmt.Errorf("invalid URL '%s': %v", lpmd.URL, err) return fmt.Errorf("invalid URL '%s': %v", lpmd.URL, err)
} }
@ -236,6 +235,7 @@ func (d *downloader) download(ctx context.Context, domain string) error {
if err := d.loadOpenPGPKeys( if err := d.loadOpenPGPKeys(
client, client,
lpmd.Document, lpmd.Document,
base,
expr, expr,
); err != nil { ); err != nil {
return err return err
@ -245,7 +245,7 @@ func (d *downloader) download(ctx context.Context, domain string) error {
client, client,
expr, expr,
lpmd.Document, lpmd.Document,
pmdURL) base)
// Do we need time range based filtering? // Do we need time range based filtering?
if d.cfg.Range != nil { if d.cfg.Range != nil {
@ -310,6 +310,7 @@ allFiles:
func (d *downloader) loadOpenPGPKeys( func (d *downloader) loadOpenPGPKeys(
client util.Client, client util.Client,
doc any, doc any,
base *url.URL,
expr *util.PathEval, expr *util.PathEval,
) error { ) error {
src, err := expr.Eval("$.public_openpgp_keys", doc) src, err := expr.Eval("$.public_openpgp_keys", doc)
@ -334,7 +335,7 @@ func (d *downloader) loadOpenPGPKeys(
if key.URL == nil { if key.URL == nil {
continue continue
} }
u, err := url.Parse(*key.URL) up, err := url.Parse(*key.URL)
if err != nil { if err != nil {
slog.Warn("Invalid URL", slog.Warn("Invalid URL",
"url", *key.URL, "url", *key.URL,
@ -342,7 +343,9 @@ func (d *downloader) loadOpenPGPKeys(
continue continue
} }
res, err := client.Get(u.String()) u := base.ResolveReference(up).String()
res, err := client.Get(u)
if err != nil { if err != nil {
slog.Warn( slog.Warn(
"Fetching public OpenPGP key failed", "Fetching public OpenPGP key failed",
@ -547,7 +550,7 @@ func (dc *downloadContext) downloadAdvisory(
tee := io.TeeReader(resp.Body, hasher) tee := io.TeeReader(resp.Body, hasher)
if err := misc.StrictJSONParse(tee, &doc); err != nil { if err := json.NewDecoder(tee).Decode(&doc); err != nil {
dc.stats.downloadFailed++ dc.stats.downloadFailed++
slog.Warn("Downloading failed", slog.Warn("Downloading failed",
"url", file.URL(), "url", file.URL(),

View file

@ -11,7 +11,6 @@ package main
import ( import (
"fmt" "fmt"
"io" "io"
"net/url"
"os" "os"
"strings" "strings"
@ -263,14 +262,6 @@ func loadConfig() (*config, error) {
if cfg.CanonicalURLPrefix == "" { if cfg.CanonicalURLPrefix == "" {
cfg.CanonicalURLPrefix = "https://" + os.Getenv("SERVER_NAME") cfg.CanonicalURLPrefix = "https://" + os.Getenv("SERVER_NAME")
} }
// Check if canonical url prefix is invalid
parsedURL, err := url.ParseRequestURI(cfg.CanonicalURLPrefix)
if err != nil {
return nil, err
}
if parsedURL.Scheme != "https" && parsedURL.Scheme != "http" {
return nil, fmt.Errorf("invalid canonical URL: %q", cfg.CanonicalURLPrefix)
}
if cfg.TLPs == nil { if cfg.TLPs == nil {
cfg.TLPs = []tlp{tlpCSAF, tlpWhite, tlpGreen, tlpAmber, tlpRed} cfg.TLPs = []tlp{tlpCSAF, tlpWhite, tlpGreen, tlpAmber, tlpRed}

View file

@ -11,6 +11,7 @@ package main
import ( import (
"bytes" "bytes"
"crypto/tls" "crypto/tls"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -81,9 +82,8 @@ func (p *processor) create() error {
} }
defer resp.Body.Close() defer resp.Body.Close()
var createError error
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
createError = fmt.Errorf("create failed: %s", resp.Status) log.Printf("Create failed: %s\n", resp.Status)
} }
var result struct { var result struct {
@ -91,7 +91,7 @@ func (p *processor) create() error {
Errors []string `json:"errors"` Errors []string `json:"errors"`
} }
if err := misc.StrictJSONParse(resp.Body, &result); err != nil { if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return err return err
} }
@ -101,7 +101,7 @@ func (p *processor) create() error {
writeStrings("Errors:", result.Errors) writeStrings("Errors:", result.Errors)
return createError return nil
} }
// uploadRequest creates the request for uploading a csaf document by passing the filename. // uploadRequest creates the request for uploading a csaf document by passing the filename.
@ -115,7 +115,7 @@ func (p *processor) uploadRequest(filename string) (*http.Request, error) {
if !p.cfg.NoSchemaCheck { if !p.cfg.NoSchemaCheck {
var doc any var doc any
if err := misc.StrictJSONParse(bytes.NewReader(data), &doc); err != nil { if err := json.NewDecoder(bytes.NewReader(data)).Decode(&doc); err != nil {
return nil, err return nil, err
} }
errs, err := csaf.ValidateCSAF(doc) errs, err := csaf.ValidateCSAF(doc)
@ -239,7 +239,7 @@ func (p *processor) process(filename string) error {
Errors []string `json:"errors"` Errors []string `json:"errors"`
} }
if err := misc.StrictJSONParse(resp.Body, &result); err != nil { if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return err return err
} }

View file

@ -10,6 +10,7 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"log" "log"
"os" "os"
@ -18,7 +19,6 @@ import (
"github.com/jessevdk/go-flags" "github.com/jessevdk/go-flags"
"github.com/gocsaf/csaf/v3/csaf" "github.com/gocsaf/csaf/v3/csaf"
"github.com/gocsaf/csaf/v3/internal/misc"
"github.com/gocsaf/csaf/v3/util" "github.com/gocsaf/csaf/v3/util"
) )
@ -301,7 +301,7 @@ func loadJSONFromFile(fname string) (any, error) {
} }
defer f.Close() defer f.Close()
var doc any var doc any
if err = misc.StrictJSONParse(f, &doc); err != nil { if err = json.NewDecoder(f).Decode(&doc); err != nil {
return nil, err return nil, err
} }
return doc, err return doc, err

View file

@ -19,7 +19,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/gocsaf/csaf/v3/internal/misc"
"github.com/gocsaf/csaf/v3/util" "github.com/gocsaf/csaf/v3/util"
) )
@ -96,7 +95,7 @@ type AdvisoryFileProcessor struct {
client util.Client client util.Client
expr *util.PathEval expr *util.PathEval
doc any doc any
pmdURL *url.URL base *url.URL
} }
// NewAdvisoryFileProcessor constructs a filename extractor // NewAdvisoryFileProcessor constructs a filename extractor
@ -105,13 +104,13 @@ func NewAdvisoryFileProcessor(
client util.Client, client util.Client,
expr *util.PathEval, expr *util.PathEval,
doc any, doc any,
pmdURL *url.URL, base *url.URL,
) *AdvisoryFileProcessor { ) *AdvisoryFileProcessor {
return &AdvisoryFileProcessor{ return &AdvisoryFileProcessor{
client: client, client: client,
expr: expr, expr: expr,
doc: doc, doc: doc,
pmdURL: pmdURL, base: base,
} }
} }
@ -180,7 +179,7 @@ func (afp *AdvisoryFileProcessor) Process(
// Not found -> fall back to PMD url // Not found -> fall back to PMD url
if empty(dirURLs) { if empty(dirURLs) {
baseURL, err := util.BaseURL(afp.pmdURL) baseURL, err := util.BaseURL(afp.base)
if err != nil { if err != nil {
return err return err
} }
@ -262,13 +261,8 @@ func (afp *AdvisoryFileProcessor) loadChanges(
continue continue
} }
pathURL, err := url.Parse(path)
if err != nil {
return nil, err
}
files = append(files, files = append(files,
DirectoryAdvisoryFile{Path: misc.JoinURL(base, pathURL).String()}) DirectoryAdvisoryFile{Path: base.JoinPath(path).String()})
} }
return files, nil return files, nil
} }
@ -282,11 +276,12 @@ func (afp *AdvisoryFileProcessor) processROLIE(
if feed.URL == nil { if feed.URL == nil {
continue continue
} }
feedURL, err := url.Parse(string(*feed.URL)) up, err := url.Parse(string(*feed.URL))
if err != nil { if err != nil {
slog.Error("Invalid URL in feed", "feed", *feed.URL, "err", err) slog.Error("Invalid URL in feed", "feed", *feed.URL, "err", err)
continue continue
} }
feedURL := afp.base.ResolveReference(up)
slog.Info("Got feed URL", "feed", feedURL) slog.Info("Got feed URL", "feed", feedURL)
fb, err := util.BaseURL(feedURL) fb, err := util.BaseURL(feedURL)
@ -294,6 +289,11 @@ func (afp *AdvisoryFileProcessor) processROLIE(
slog.Error("Invalid feed base URL", "url", fb, "err", err) slog.Error("Invalid feed base URL", "url", fb, "err", err)
continue continue
} }
feedBaseURL, err := url.Parse(fb)
if err != nil {
slog.Error("Cannot parse feed base URL", "url", fb, "err", err)
continue
}
res, err := afp.client.Get(feedURL.String()) res, err := afp.client.Get(feedURL.String())
if err != nil { if err != nil {
@ -325,7 +325,7 @@ func (afp *AdvisoryFileProcessor) processROLIE(
slog.Error("Invalid URL", "url", u, "err", err) slog.Error("Invalid URL", "url", u, "err", err)
return "" return ""
} }
return p.String() return feedBaseURL.ResolveReference(p).String()
} }
rfeed.Entries(func(entry *Entry) { rfeed.Entries(func(entry *Entry) {

View file

@ -14,8 +14,6 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"github.com/gocsaf/csaf/v3/internal/misc"
) )
// Acknowledgement reflects the 'acknowledgement' object in the list of acknowledgements. // Acknowledgement reflects the 'acknowledgement' object in the list of acknowledgements.
@ -385,6 +383,7 @@ type Relationship struct {
FullProductName *FullProductName `json:"full_product_name"` // required FullProductName *FullProductName `json:"full_product_name"` // required
ProductReference *ProductID `json:"product_reference"` // required ProductReference *ProductID `json:"product_reference"` // required
RelatesToProductReference *ProductID `json:"relates_to_product_reference"` // required RelatesToProductReference *ProductID `json:"relates_to_product_reference"` // required
} }
// Relationships is a list of Relationship. // Relationships is a list of Relationship.
@ -444,11 +443,10 @@ var csafFlagLabelPattern = alternativesUnmarshal(
// machine readable flag. For example, this could be a machine readable justification // machine readable flag. For example, this could be a machine readable justification
// code why a product is not affected. // code why a product is not affected.
type Flag struct { type Flag struct {
Date *string `json:"date,omitempty"` Date *string `json:"date,omitempty"`
GroupIDs *ProductGroups `json:"group_ids,omitempty"` GroupIDs *ProductGroups `json:"group_ids,omitempty"`
Label *FlagLabel `json:"label"` // required Label *FlagLabel `json:"label"` // required
//revive:disable-next-line:var-naming until new major version w fix ProductIds *Products `json:"product_ids,omitempty"`
ProductIds *Products `json:"product_ids,omitempty"`
} }
// Flags is a list if Flag elements. // Flags is a list if Flag elements.
@ -607,16 +605,14 @@ type RestartRequired struct {
// Remediation specifies details on how to handle (and presumably, fix) a vulnerability. // Remediation specifies details on how to handle (and presumably, fix) a vulnerability.
type Remediation struct { type Remediation struct {
Category *RemediationCategory `json:"category"` // required Category *RemediationCategory `json:"category"` // required
Date *string `json:"date,omitempty"` Date *string `json:"date,omitempty"`
Details *string `json:"details"` // required Details *string `json:"details"` // required
Entitlements []*string `json:"entitlements,omitempty"` Entitlements []*string `json:"entitlements,omitempty"`
//revive:disable:var-naming until new major version w fix GroupIds *ProductGroups `json:"group_ids,omitempty"`
GroupIds *ProductGroups `json:"group_ids,omitempty"` ProductIds *Products `json:"product_ids,omitempty"`
ProductIds *Products `json:"product_ids,omitempty"` RestartRequired *RestartRequired `json:"restart_required,omitempty"`
//revive:enable URL *string `json:"url,omitempty"`
RestartRequired *RestartRequired `json:"restart_required,omitempty"`
URL *string `json:"url,omitempty"`
} }
// Remediations is a list of Remediation elements. // Remediations is a list of Remediation elements.
@ -742,13 +738,11 @@ var csafThreatCategoryPattern = alternativesUnmarshal(
// Threat contains information about a vulnerability that can change with time. // Threat contains information about a vulnerability that can change with time.
type Threat struct { type Threat struct {
Category *ThreatCategory `json:"category"` // required Category *ThreatCategory `json:"category"` // required
Date *string `json:"date,omitempty"` Date *string `json:"date,omitempty"`
Details *string `json:"details"` // required Details *string `json:"details"` // required
//revive:disable:var-naming until new major version w fix GroupIds *ProductGroups `json:"group_ids,omitempty"`
GroupIds *ProductGroups `json:"group_ids,omitempty"` ProductIds *Products `json:"product_ids,omitempty"`
ProductIds *Products `json:"product_ids,omitempty"`
//revive:enable
} }
// Threats is a list of Threat elements. // Threats is a list of Threat elements.
@ -891,8 +885,8 @@ func (rs Revisions) Validate() error {
// Validate validates an Engine. // Validate validates an Engine.
func (e *Engine) Validate() error { func (e *Engine) Validate() error {
if e.Name == nil { if e.Version == nil {
return errors.New("'name' is missing") return errors.New("'version' is missing")
} }
return nil return nil
} }
@ -1397,7 +1391,7 @@ func LoadAdvisory(fname string) (*Advisory, error) {
} }
defer f.Close() defer f.Close()
var advisory Advisory var advisory Advisory
if err := misc.StrictJSONParse(f, &advisory); err != nil { if err := json.NewDecoder(f).Decode(&advisory); err != nil {
return nil, err return nil, err
} }
if err := advisory.Validate(); err != nil { if err := advisory.Validate(); err != nil {

View file

@ -1,46 +0,0 @@
package csaf
import (
"os"
"path/filepath"
"testing"
)
func TestLoadAdvisory(t *testing.T) {
type args struct {
jsonDir string
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "Valid documents",
args: args{jsonDir: "csaf-documents/valid"},
wantErr: false,
},
{
name: "Garbage trailing data",
args: args{jsonDir: "csaf-documents/trailing-garbage-data"},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := filepath.Walk("../testdata/"+tt.args.jsonDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.Mode().IsRegular() && filepath.Ext(info.Name()) == ".json" {
if _, err := LoadAdvisory(path); (err != nil) != tt.wantErr {
t.Errorf("LoadAdvisory() error = %v, wantErr %v", err, tt.wantErr)
}
}
return nil
}); err != nil {
t.Fatal(err)
}
})
}
}

View file

@ -6,11 +6,7 @@
// SPDX-FileCopyrightText: 2023 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de> // SPDX-FileCopyrightText: 2023 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
// Software-Engineering: 2023 Intevation GmbH <https://intevation.de> // Software-Engineering: 2023 Intevation GmbH <https://intevation.de>
// Package csaf contains the core data models used by the csaf distribution // Package csaf contains the core data models used by the csaf distribution.
// tools.
//
// See https://github.com/gocsaf/csaf/tab=readme-ov-file#use-as-go-library
// about hints and limits for its use as a library.
package csaf package csaf
//go:generate go run ./generate_cvss_enums.go -o cvss20enums.go -i ./schema/cvss-v2.0.json -p CVSS20 //go:generate go run ./generate_cvss_enums.go -o cvss20enums.go -i ./schema/cvss-v2.0.json -p CVSS20

View file

@ -12,6 +12,7 @@ package main
import ( import (
"bytes" "bytes"
"encoding/json"
"flag" "flag"
"fmt" "fmt"
"go/format" "go/format"
@ -21,8 +22,6 @@ import (
"sort" "sort"
"strings" "strings"
"text/template" "text/template"
"github.com/gocsaf/csaf/v3/internal/misc"
) )
// We from Intevation consider the source code parts in the following // We from Intevation consider the source code parts in the following
@ -99,7 +98,7 @@ func loadSchema(filename string) (*schema, error) {
} }
defer f.Close() defer f.Close()
var s schema var s schema
if err := misc.StrictJSONParse(f, &s); err != nil { if err := json.NewDecoder(f).Decode(&s); err != nil {
return nil, err return nil, err
} }
return &s, nil return &s, nil

View file

@ -17,7 +17,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/gocsaf/csaf/v3/internal/misc"
"github.com/gocsaf/csaf/v3/util" "github.com/gocsaf/csaf/v3/util"
) )
@ -576,6 +575,7 @@ func (d *Distribution) Validate() error {
// Validate checks if the provider metadata is valid. // Validate checks if the provider metadata is valid.
// Returns an error if the validation fails otherwise nil. // Returns an error if the validation fails otherwise nil.
func (pmd *ProviderMetadata) Validate() error { func (pmd *ProviderMetadata) Validate() error {
switch { switch {
case pmd.CanonicalURL == nil: case pmd.CanonicalURL == nil:
return errors.New("canonical_url is mandatory") return errors.New("canonical_url is mandatory")
@ -695,7 +695,8 @@ func (pmd *ProviderMetadata) WriteTo(w io.Writer) (int64, error) {
func LoadProviderMetadata(r io.Reader) (*ProviderMetadata, error) { func LoadProviderMetadata(r io.Reader) (*ProviderMetadata, error) {
var pmd ProviderMetadata var pmd ProviderMetadata
if err := misc.StrictJSONParse(r, &pmd); err != nil { dec := json.NewDecoder(r)
if err := dec.Decode(&pmd); err != nil {
return nil, err return nil, err
} }

View file

@ -11,13 +11,13 @@ package csaf
import ( import (
"bytes" "bytes"
"crypto/sha256" "crypto/sha256"
"encoding/json"
"fmt" "fmt"
"io" "io"
"log/slog" "log/slog"
"net/http" "net/http"
"strings" "strings"
"github.com/gocsaf/csaf/v3/internal/misc"
"github.com/gocsaf/csaf/v3/util" "github.com/gocsaf/csaf/v3/util"
) )
@ -33,7 +33,7 @@ type ProviderMetadataLoader struct {
type ProviderMetadataLoadMessageType int type ProviderMetadataLoadMessageType int
const ( const (
// JSONDecodingFailed indicates problems with JSON decoding //JSONDecodingFailed indicates problems with JSON decoding
JSONDecodingFailed ProviderMetadataLoadMessageType = iota JSONDecodingFailed ProviderMetadataLoadMessageType = iota
// SchemaValidationFailed indicates a general problem with schema validation. // SchemaValidationFailed indicates a general problem with schema validation.
SchemaValidationFailed SchemaValidationFailed
@ -149,6 +149,7 @@ func (pmdl *ProviderMetadataLoader) Enumerate(domain string) []*LoadedProviderMe
} }
dnsURL := "https://csaf.data.security." + domain dnsURL := "https://csaf.data.security." + domain
return []*LoadedProviderMetadata{pmdl.loadFromURL(dnsURL)} return []*LoadedProviderMetadata{pmdl.loadFromURL(dnsURL)}
} }
// Load loads one valid provider metadata for a given path. // Load loads one valid provider metadata for a given path.
@ -322,7 +323,7 @@ func (pmdl *ProviderMetadataLoader) loadFromURL(path string) *LoadedProviderMeta
var doc any var doc any
if err := misc.StrictJSONParse(tee, &doc); err != nil { if err := json.NewDecoder(tee).Decode(&doc); err != nil {
result.Messages.Add( result.Messages.Add(
JSONDecodingFailed, JSONDecodingFailed,
fmt.Sprintf("JSON decoding failed: %v", err)) fmt.Sprintf("JSON decoding failed: %v", err))

View file

@ -18,7 +18,6 @@ import (
"net/http" "net/http"
"sync" "sync"
"github.com/gocsaf/csaf/v3/internal/misc"
bolt "go.etcd.io/bbolt" bolt "go.etcd.io/bbolt"
) )
@ -181,6 +180,7 @@ func prepareCache(config string) (cache, error) {
return create() return create()
} }
return nil return nil
}); err != nil { }); err != nil {
db.Close() db.Close()
return nil, err return nil, err
@ -256,7 +256,7 @@ func deserialize(value []byte) (*RemoteValidationResult, error) {
} }
defer r.Close() defer r.Close()
var rvr RemoteValidationResult var rvr RemoteValidationResult
if err := misc.StrictJSONParse(r, &rvr); err != nil { if err := json.NewDecoder(r).Decode(&rvr); err != nil {
return nil, err return nil, err
} }
return &rvr, nil return &rvr, nil
@ -323,7 +323,7 @@ func (v *remoteValidator) Validate(doc any) (*RemoteValidationResult, error) {
// no cache -> process directly. // no cache -> process directly.
in = resp.Body in = resp.Body
} }
return misc.StrictJSONParse(in, &rvr) return json.NewDecoder(in).Decode(&rvr)
}(); err != nil { }(); err != nil {
return nil, err return nil, err
} }

View file

@ -14,7 +14,6 @@ import (
"sort" "sort"
"time" "time"
"github.com/gocsaf/csaf/v3/internal/misc"
"github.com/gocsaf/csaf/v3/util" "github.com/gocsaf/csaf/v3/util"
) )
@ -55,7 +54,7 @@ type ROLIEServiceDocument struct {
// LoadROLIEServiceDocument loads a ROLIE service document from a reader. // LoadROLIEServiceDocument loads a ROLIE service document from a reader.
func LoadROLIEServiceDocument(r io.Reader) (*ROLIEServiceDocument, error) { func LoadROLIEServiceDocument(r io.Reader) (*ROLIEServiceDocument, error) {
var rsd ROLIEServiceDocument var rsd ROLIEServiceDocument
if err := misc.StrictJSONParse(r, &rsd); err != nil { if err := json.NewDecoder(r).Decode(&rsd); err != nil {
return nil, err return nil, err
} }
return &rsd, nil return &rsd, nil
@ -123,7 +122,7 @@ func (rcd *ROLIECategoryDocument) Merge(categories ...string) bool {
// LoadROLIECategoryDocument loads a ROLIE category document from a reader. // LoadROLIECategoryDocument loads a ROLIE category document from a reader.
func LoadROLIECategoryDocument(r io.Reader) (*ROLIECategoryDocument, error) { func LoadROLIECategoryDocument(r io.Reader) (*ROLIECategoryDocument, error) {
var rcd ROLIECategoryDocument var rcd ROLIECategoryDocument
if err := misc.StrictJSONParse(r, &rcd); err != nil { if err := json.NewDecoder(r).Decode(&rcd); err != nil {
return nil, err return nil, err
} }
return &rcd, nil return &rcd, nil
@ -169,22 +168,14 @@ type Format struct {
// Entry for ROLIE. // Entry for ROLIE.
type Entry struct { type Entry struct {
Base *string `json:"base,omitempty"` ID string `json:"id"`
LanguageTag *string `json:"lang,omitempty"` Titel string `json:"title"`
Author *json.RawMessage `json:"author,omitempty"` Link []Link `json:"link"`
Category []ROLIECategory `json:"category,omitempty"` Published TimeStamp `json:"published"`
Content Content `json:"content"` Updated TimeStamp `json:"updated"`
Contributor *json.RawMessage `json:"contributor,omitempty"` Summary *Summary `json:"summary,omitempty"`
ID string `json:"id"` Content Content `json:"content"`
Link []Link `json:"link"` Format Format `json:"format"`
Published TimeStamp `json:"published"`
Rights *json.RawMessage `json:"rights,omitempty"`
Source *json.RawMessage `json:"source,omitempty"`
Summary *Summary `json:"summary,omitempty"`
Titel string `json:"title"`
Updated TimeStamp `json:"updated"`
Format Format `json:"format"`
Property *json.RawMessage `json:"property,omitempty"`
} }
// FeedData is the content of the ROLIE feed. // FeedData is the content of the ROLIE feed.
@ -204,8 +195,9 @@ type ROLIEFeed struct {
// LoadROLIEFeed loads a ROLIE feed from a reader. // LoadROLIEFeed loads a ROLIE feed from a reader.
func LoadROLIEFeed(r io.Reader) (*ROLIEFeed, error) { func LoadROLIEFeed(r io.Reader) (*ROLIEFeed, error) {
dec := json.NewDecoder(r)
var rf ROLIEFeed var rf ROLIEFeed
if err := misc.StrictJSONParse(r, &rf); err != nil { if err := dec.Decode(&rf); err != nil {
return nil, err return nil, err
} }
return &rf, nil return &rf, nil

View file

@ -10,17 +10,13 @@ package csaf
import ( import (
"bytes" "bytes"
"crypto/tls"
_ "embed" // Used for embedding. _ "embed" // Used for embedding.
"errors" "io"
"fmt"
"net/http"
"sort" "sort"
"strings" "strings"
"sync" "sync"
"time"
"github.com/santhosh-tekuri/jsonschema/v6" "github.com/santhosh-tekuri/jsonschema/v5"
) )
//go:embed schema/csaf_json_schema.json //go:embed schema/csaf_json_schema.json
@ -68,28 +64,13 @@ var (
compiledRolieSchema = compiledSchema{url: rolieSchemaURL} compiledRolieSchema = compiledSchema{url: rolieSchemaURL}
) )
type schemaLoader http.Client // loadURL loads the content of an URL from embedded data or
// falls back to the global loader function of the jsonschema package.
func (l *schemaLoader) loadHTTPURL(url string) (any, error) { func loadURL(s string) (io.ReadCloser, error) {
client := (*http.Client)(l) loader := func(data []byte) (io.ReadCloser, error) {
resp, err := client.Get(url) return io.NopCloser(bytes.NewReader(data)), nil
if err != nil {
return nil, err
} }
defer resp.Body.Close() switch s {
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%s returned status code %d", url, resp.StatusCode)
}
return jsonschema.UnmarshalJSON(resp.Body)
}
// Load loads the schema from the specified url.
func (l *schemaLoader) Load(url string) (any, error) {
loader := func(data []byte) (any, error) {
return jsonschema.UnmarshalJSON(bytes.NewReader(data))
}
switch url {
case csafSchemaURL: case csafSchemaURL:
return loader(csafSchema) return loader(csafSchema)
case cvss20SchemaURL: case cvss20SchemaURL:
@ -105,27 +86,14 @@ func (l *schemaLoader) Load(url string) (any, error) {
case rolieSchemaURL: case rolieSchemaURL:
return loader(rolieSchema) return loader(rolieSchema)
default: default:
// Fallback to http loader return jsonschema.LoadURL(s)
return l.loadHTTPURL(url)
} }
} }
func newSchemaLoader(insecure bool) *schemaLoader {
httpLoader := schemaLoader(http.Client{
Timeout: 15 * time.Second,
})
if insecure {
httpLoader.Transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
}
return &httpLoader
}
func (cs *compiledSchema) compile() { func (cs *compiledSchema) compile() {
c := jsonschema.NewCompiler() c := jsonschema.NewCompiler()
c.AssertFormat() c.AssertFormat = true
c.UseLoader(newSchemaLoader(false)) c.LoadURL = loadURL
cs.compiled, cs.err = c.Compile(cs.url) cs.compiled, cs.err = c.Compile(cs.url)
} }
@ -141,8 +109,7 @@ func (cs *compiledSchema) validate(doc any) ([]string, error) {
return nil, nil return nil, nil
} }
var valErr *jsonschema.ValidationError valErr, ok := err.(*jsonschema.ValidationError)
ok := errors.As(err, &valErr)
if !ok { if !ok {
return nil, err return nil, err
} }
@ -166,21 +133,21 @@ func (cs *compiledSchema) validate(doc any) ([]string, error) {
if pi != pj { if pi != pj {
return pi < pj return pi < pj
} }
return errs[i].Error.String() < errs[j].Error.String() return errs[i].Error < errs[j].Error
}) })
res := make([]string, 0, len(errs)) res := make([]string, 0, len(errs))
for i := range errs { for i := range errs {
e := &errs[i] e := &errs[i]
if e.Error == nil { if e.Error == "" {
continue continue
} }
loc := e.InstanceLocation loc := e.InstanceLocation
if loc == "" { if loc == "" {
loc = e.AbsoluteKeywordLocation loc = e.AbsoluteKeywordLocation
} }
res = append(res, loc+": "+e.Error.String()) res = append(res, loc+": "+e.Error)
} }
return res, nil return res, nil

View file

@ -3,7 +3,7 @@
## Supported Go versions ## Supported Go versions
We support the latest version and the one before We support the latest version and the one before
the latest version of Go (currently 1.24 and 1.25). the latest version of Go (currently 1.23 and 1.24).
## Generated files ## Generated files

View file

@ -247,9 +247,3 @@ insecure = true
In case you want to provide CSAF advisories from others In case you want to provide CSAF advisories from others
that only qualify as CSAF publishers, see that only qualify as CSAF publishers, see
[how to use the `csaf_aggregator` as "CSAF proxy provider"](proxy-provider-for-aggregator.md). [how to use the `csaf_aggregator` as "CSAF proxy provider"](proxy-provider-for-aggregator.md).
Some providers may limit the rate of requests that may be sent to retrieve advisories.
This may cause issues with the aggregator.
In this case, the --rate option can be used to adjust the requests per second
sent by each worker of the aggregator to an acceptable rate.
(The rate that is considered acceptable depends on the provider.)

View file

@ -78,13 +78,6 @@ The option `timerange` allows to only check advisories from a given time
interval. It can only be given once. See the interval. It can only be given once. See the
[downloader documentation](csaf_downloader.md#timerange-option) for details. [downloader documentation](csaf_downloader.md#timerange-option) for details.
Some providers may limit the rate of requests that may be sent to retrieve advisories.
This may cause the checker to be unable to retrieve all advisories. In this case,
the --rate option can be used to adjust the requests per second
sent by the checker to an acceptable rate.
(The rate that is considered acceptable depends on the provider.)
You can ignore certain advisories while checking by specifying a list You can ignore certain advisories while checking by specifying a list
of regular expressions[^1] to match their URLs by using the `ignorepattern` of regular expressions[^1] to match their URLs by using the `ignorepattern`
option. option.

View file

@ -51,12 +51,6 @@ to download more advisories at once. This may improve the overall speed of the d
However, since this also increases the load on the servers, their administrators could However, since this also increases the load on the servers, their administrators could
have taken countermeasures to limit this. have taken countermeasures to limit this.
For example, some providers may limit the rate of requests that may be sent to retrieve advisories.
This may cause the downloader to be unable to retrieve all advisories.
In this case, the --rate option can be used to adjust the requests per second
sent by the downloader to an acceptable rate.
(The rate that is considered acceptable depends on the provider.)
If no config file is explictly given the follwing places are searched for a config file: If no config file is explictly given the follwing places are searched for a config file:
``` ```
@ -75,7 +69,7 @@ insecure = false
# client_cert # not set by default # client_cert # not set by default
# client_key # not set by default # client_key # not set by default
# client_passphrase # not set by default # client_passphrase # not set by default
ignore_sigcheck = false ignoresigcheck = false
# rate # set to unlimited # rate # set to unlimited
worker = 2 worker = 2
# time_range # not set by default # time_range # not set by default
@ -110,9 +104,8 @@ ignorepattern = [".*white.*", ".*red.*"]
#### Timerange option #### Timerange option
The `time_range` parameter enables downloading advisories The `timerange` parameter enables downloading advisories which last changes falls
which last changes falls into a given intervall. into a given intervall. There are three possible notations:
There are three possible notations:
1. Relative. If the given string follows the rules of a 1. Relative. If the given string follows the rules of a
[Go duration](https://pkg.go.dev/time@go1.20.6#ParseDuration), [Go duration](https://pkg.go.dev/time@go1.20.6#ParseDuration),

View file

@ -58,8 +58,7 @@ The following example file documents all available configuration options:
# The following shows an example of a manually set prefix: # The following shows an example of a manually set prefix:
#canonical_url_prefix = "https://localhost" #canonical_url_prefix = "https://localhost"
# Require users to use both # Require users to use a password and a valid Client Certificate for write access.
# (1) a password and (2) a valid Client Certificate for write access.
#certificate_and_password = false #certificate_and_password = false
# Allow the user to send the request without having to send a passphrase # Allow the user to send the request without having to send a passphrase

View file

@ -144,7 +144,7 @@ on a GNU/Linux operating system.
Create the folders: Create the folders:
```(shell) ```(shell)
curl https://192.168.56.102/cgi-bin/csaf_provider.go/api/create --cert-type p12 --cert {clientCertificat.p12} curl https://192.168.56.102/cgi-bin/csaf_provider.go/create --cert-type p12 --cert {clientCertificat.p12}
``` ```
Replace {clientCertificate.p12} with the client certificate file Replace {clientCertificate.p12} with the client certificate file
in pkcs12 format which includes the corresponding key as well. in pkcs12 format which includes the corresponding key as well.

View file

@ -1,5 +1,5 @@
Scripts for assisting the Integration tests. Scripts for assisting the Integration tests.
They were written on Ubuntu 20.04 LTS amd64 and also tested with 24.04 LTS. They were written on Ubuntu 20.04 TLS amd64 and also tested with 24.04 TLS.
- `prepareUbuntuInstanceForITests.sh` installs the required packages for the csaf integration tests on a naked Ubuntu LTS amd64. - `prepareUbuntuInstanceForITests.sh` installs the required packages for the csaf integration tests on a naked Ubuntu LTS amd64.
@ -8,9 +8,9 @@ and configures nginx for serving TLS connections.
- `TLSClientConfigsForITest.sh` generates client certificates by calling `createCCForITest.sh` which uses the root certificate initialized before with `createRootCAForITest.sh`. It configures nginx to enable the authentication with client certificate. (This assumes that the same folder name is used to create the root certificate) - `TLSClientConfigsForITest.sh` generates client certificates by calling `createCCForITest.sh` which uses the root certificate initialized before with `createRootCAForITest.sh`. It configures nginx to enable the authentication with client certificate. (This assumes that the same folder name is used to create the root certificate)
- `setupProviderForITest.sh` builds the `csaf_provider`, writes the required nginx configurations and create the initial folders. IT calls `uploadToProvider.sh` to upload some csaf example files to the provider. - `setupProviderForITest.sh` builds the csaf_provider, writes the required nginx configurations and create the initial folders. IT calls `uploadToProvider.sh` to upload some csaf example files to the provider.
As creating the folders needs to authenticate with the `csaf_provider`, the configurations of TLS server and Client certificate authentication should be set. So it is recommended to call the scripts in this order: `TLSConfigsForITest.sh`, `TLSClientConfigsForITest.sh`, `setupProviderForITest.sh` As creating the folders needs to authenticate with the csaf_provider, the configurations of TLS server and Client certificate authentication should be set. So it is recommended to call the scripts in this order: `TLSConfigsForITest.sh`, `TLSClientConfigsForITest.sh`, `setupProviderForITest.sh`
Calling example (as user with sudo privileges): Calling example (as user with sudo privileges):
``` bash ``` bash

34
go.mod
View file

@ -1,33 +1,31 @@
module github.com/gocsaf/csaf/v3 module github.com/gocsaf/csaf/v3
go 1.24.9 go 1.22.9
toolchain go1.25.3
require ( require (
github.com/BurntSushi/toml v1.5.0 github.com/BurntSushi/toml v1.4.0
github.com/Intevation/gval v1.3.0 github.com/Intevation/gval v1.3.0
github.com/Intevation/jsonpath v0.2.1 github.com/Intevation/jsonpath v0.2.1
github.com/ProtonMail/gopenpgp/v2 v2.9.0 github.com/ProtonMail/gopenpgp/v2 v2.8.0
github.com/PuerkitoBio/goquery v1.11.0 github.com/PuerkitoBio/goquery v1.8.1
github.com/gofrs/flock v0.13.0 github.com/gofrs/flock v0.12.1
github.com/jessevdk/go-flags v1.6.1 github.com/jessevdk/go-flags v1.6.1
github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-homedir v1.1.0
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
go.etcd.io/bbolt v1.4.3 go.etcd.io/bbolt v1.3.11
golang.org/x/crypto v0.46.0 golang.org/x/crypto v0.29.0
golang.org/x/term v0.38.0 golang.org/x/term v0.26.0
golang.org/x/time v0.14.0 golang.org/x/time v0.8.0
) )
require ( require (
github.com/ProtonMail/go-crypto v1.3.0 // indirect github.com/ProtonMail/go-crypto v1.1.2 // indirect
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect
github.com/andybalholm/cascadia v1.3.3 // indirect github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/cloudflare/circl v1.6.1 // indirect github.com/cloudflare/circl v1.5.0 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/shopspring/decimal v1.4.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect
golang.org/x/net v0.48.0 // indirect golang.org/x/net v0.31.0 // indirect
golang.org/x/sys v0.39.0 // indirect golang.org/x/sys v0.27.0 // indirect
golang.org/x/text v0.32.0 // indirect golang.org/x/text v0.20.0 // indirect
) )

114
go.sum
View file

@ -1,30 +1,28 @@
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/Intevation/gval v1.3.0 h1:+Ze5sft5MmGbZrHj06NVUbcxCb67l9RaPTLMNr37mjw= github.com/Intevation/gval v1.3.0 h1:+Ze5sft5MmGbZrHj06NVUbcxCb67l9RaPTLMNr37mjw=
github.com/Intevation/gval v1.3.0/go.mod h1:xmGyGpP5be12EL0P12h+dqiYG8qn2j3PJxIgkoOHO5o= github.com/Intevation/gval v1.3.0/go.mod h1:xmGyGpP5be12EL0P12h+dqiYG8qn2j3PJxIgkoOHO5o=
github.com/Intevation/jsonpath v0.2.1 h1:rINNQJ0Pts5XTFEG+zamtdL7l9uuE1z0FBA+r55Sw+A= github.com/Intevation/jsonpath v0.2.1 h1:rINNQJ0Pts5XTFEG+zamtdL7l9uuE1z0FBA+r55Sw+A=
github.com/Intevation/jsonpath v0.2.1/go.mod h1:WnZ8weMmwAx/fAO3SutjYFU+v7DFreNYnibV7CiaYIw= github.com/Intevation/jsonpath v0.2.1/go.mod h1:WnZ8weMmwAx/fAO3SutjYFU+v7DFreNYnibV7CiaYIw=
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw= github.com/ProtonMail/go-crypto v1.1.2 h1:A7JbD57ThNqh7XjmHE+PXpQ3Dqt3BrSAC0AL0Go3KS0=
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= github.com/ProtonMail/go-crypto v1.1.2/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k= github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k=
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw= github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=
github.com/ProtonMail/gopenpgp/v2 v2.9.0 h1:ruLzBmwe4dR1hdnrsEJ/S7psSBmV15gFttFUPP/+/kE= github.com/ProtonMail/gopenpgp/v2 v2.8.0 h1:WvMv3CMcFsqKSM4/Qf8sf3tgyQkzDqQmoSE49bnBuP4=
github.com/ProtonMail/gopenpgp/v2 v2.9.0/go.mod h1:IldDyh9Hv1ZCCYatTuuEt1XZJ0OPjxLpTarDfglih7s= github.com/ProtonMail/gopenpgp/v2 v2.8.0/go.mod h1:qb2GUSnmA9ipBW5GVtCtEhkummSlqs2A8Ar3S0HBgSY=
github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw= github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
github.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ= github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA= github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4= github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc= github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@ -33,93 +31,67 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo= go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E= go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View file

@ -20,13 +20,13 @@ func TestLoadCertificates(t *testing.T) {
passphrase = "qwer" passphrase = "qwer"
missingCert = "data/testclientcert_missing.crt" missingCert = "data/testclientcert_missing.crt"
missingTestkey = "data/testclientkey_missing.pem" missingTestkey = "data/testclientkey_missing.pem"
privateKey = "data/private.pem" privateKey = "data/privated.pem"
privateCert = "data/cert.crt" privateCert = "data/cert.crt"
) )
// Try to load cert that is not protected, expect success. // Try to load cert that is not protected, expect success.
if cert, err := LoadCertificate(&testCert, &testKey, nil); cert == nil || err != nil { if cert, err := LoadCertificate(&testCert, &testKey, nil); cert == nil || err != nil {
t.Errorf("Failure: Couldn't load supposedly valid certificate. Got error: %v", err) t.Errorf("Failure: Couldn't load supposedly valid certificate.")
} }
// Try to load no cert, expect error. // Try to load no cert, expect error.
if cert, err := LoadCertificate(nil, &testKey, nil); cert != nil || err == nil { if cert, err := LoadCertificate(nil, &testKey, nil); cert != nil || err == nil {
@ -46,7 +46,7 @@ func TestLoadCertificates(t *testing.T) {
} }
// Try to load encrypted cert, expecting success. // Try to load encrypted cert, expecting success.
if cert, err := LoadCertificate(&privateCert, &privateKey, &passphrase); cert == nil || err != nil { if cert, err := LoadCertificate(&privateCert, &privateKey, &passphrase); cert == nil || err != nil {
t.Errorf("Failure: Couldn't load supposedly valid encrypted certificate. Got error: %v", err) t.Errorf("Failure: Couldn't load supposedly valid encrypted certificate.")
} }
// Try to load wrong encrypted cert, expecting error. // Try to load wrong encrypted cert, expecting error.
if cert, err := LoadCertificate(&testKey, &privateKey, &passphrase); cert != nil || err == nil { if cert, err := LoadCertificate(&testKey, &privateKey, &passphrase); cert != nil || err == nil {
@ -56,8 +56,8 @@ func TestLoadCertificates(t *testing.T) {
if cert, err := LoadCertificate(&missingCert, &privateKey, &passphrase); cert != nil || err == nil { if cert, err := LoadCertificate(&missingCert, &privateKey, &passphrase); cert != nil || err == nil {
t.Errorf("Failure: No Failure while loading nonexistens certificate.") t.Errorf("Failure: No Failure while loading nonexistens certificate.")
} }
// Try to load nonexistent encrypted cert, expecting success. // Try to load nonexistent encrypted cert, expecting error.
if cert, err := LoadCertificate(nil, nil, nil); cert != nil || err != nil { if cert, err := LoadCertificate(nil, nil, nil); cert != nil || err != nil {
t.Errorf("Failure: Expected nil return. Got error: %v", err) t.Errorf("Failure: Expected nil return.")
} }
} }

View file

@ -1,60 +0,0 @@
#!/bin/bash
#
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: 2025 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
# Software-Engineering: 2025 Intevation GmbH <https://intevation.de>
# cab be used to generated the certificates for the go tests
# as the resulting files are in the repository, this script does not
# need to be run each time, its purpose is to document how the keys and
# certs were created
set -e
certtool --generate-privkey --outfile testserver-key.pem
echo '
organization = "CSAF"
unit = "CSAF Distribution"
country = "DE"
cn = "csaf.test"
dns_name = "csaf.test"
dns_name = "localhost"
dns_name = "*.csaf.test"
ip_address = "127.0.0.1"
ip_address = "::1"
tls_www_server
tls_www_client
ocsp_signing_key
encryption_key
signing_key
expiration_days = 36500
' > gnutls-certtool.testserver.template
certtool --generate-self-signed --load-privkey testserver-key.pem --outfile cert.crt --template gnutls-certtool.testserver.template --stdout | head -1
# for testing legacy code path, we use openssl's traditional mode to
# create a password protected variant after RFC 1423 that still can be read
# by https://pkg.go.dev/crypto/x509#DecryptPEMBlock. Citation:
# Legacy PEM encryption as specified in RFC 1423 is insecure by design.
# Since it does not authenticate the ciphertext, it is vulnerable
# to padding oracle attacks that can let an attacker recover the plaintext.
openssl rsa -in testserver-key.pem -out private.pem -aes256 -passout pass:qwer -traditional
echo '
organization = "CSAF Tools Development (internal)"
country = "DE"
cn = "Tester"
tls_www_client
encryption_key
signing_key
expiration_days = 36500
' > gnutls-certtool.testclientkey.template
certtool --generate-privkey --bits 3072 --outfile testclientkey.pem
certtool --generate-self-signed --load-privkey testclientkey.pem --template gnutls-certtool.testclientkey.template --outfile testclient.crt

View file

@ -1,28 +1,37 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
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
c9SoHpWzh1ZuzfiBYa/cdQNUtaTfgHLi5GYtV1DzmKXVRUciBiNBWWxYMbTGvTOO t4IrYSBkbnNOYW1lIG9mIHRoZSBzdWJqZWN0IG9mIHRoZSBjZXJ0aWZpY2F0ZYI3
i3r6DEgOYuukeL4qj//EGOcTJEarHVSxPMuXTD/PoP/VpIdqRS9drEpFUC6lecZc YW4gYWRkaXRpb25hbCBkbnNOYW1lIG9mIHRoZSBzdWJqZWN0IG9mIHRoZSBjZXJ0
UJtUPAcyx0oD2vNmPmulDfYFMLLOPrIeNa0g7os4wgUl7+9wR1cPPRTXY0fW6Hoi aWZpY2F0ZYIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIP
j+a8Qn80Q3PrOuEO/SZ4aHHpOk90bRqofyIhFjPwS0YN5w/Sn23uq1u2Dx+Zy+5K c2Vjb25kIGFkZGl0aW9ugg50aGlyZCBhZGRpdGlvboIHZG5zTmFtZTAMBgNVHRMB
6Cs9p5dJWu5/zU4ZdbQlpYIHXQVbido1TY92Z84skEsac2wVh7L2LMB3p3Gu9WYn Af8EAjAAMDEGA1UdJQQqMCgGCCsGAQUFBwMJBggrBgEFBQcDAgYIKwYBBQUHAwEG
oKqFYCw5FICvRgyh1KG8QWhW59Em0Jxr8rTw6qyBQACdixKy6/1ok2ArMivTC8Gd CCsGAQUFBwMCMA8GA1UdDwEB/wQFAwMHsAAwHQYDVR0OBBYEFKrFhODjTKCopb+W
rEbefshgc6dnAZCAp1MjCU+tg9iYEymSSLdOtUKvHEIosUGO1p5ol0hReTQ= Qa29PsHR4HXgMB8GA1UdIwQYMBaAFCyZxCa1ZUHVy8LjikE8zumAiEgfMA0GCSqG
SIb3DQEBCwUAA4IBgQBTrAgh6d+qiLumEfmkNCmhewxKxDZp+Ni2nz9XRzNO2cQE
U0n8MdbnQInW3xJXng2sAcl1fQz0RN1hkyjDwi69mbbPgcTYmxJFvyt+zRYBe/Sq
4CGGkxEdPW94tMpQ6SrCn2mAMnvcq9A1pYBVYyPeUsaRHC5OUBFOMCevNy8JwNyY
MJ0H5HQCyCysbzA1d521pogGUs/tmbE+ym9zpV8vG0b6De1PexjVeGkTNYz6NCR2
VZTQ+OJ5iE5pHPEC1Qif44LrR9Kdn/wu3RjTYyHeBOJFjK+DKgleNF4QVTcZQIPE
snN4H+/VSgTZQ3kgWbtpd1m5oRBJovEc2Qe+l+iDFCk8OA4z/x+fkvOeD3NUAl7D
9Pt3cP3UtWUJp4NJn2dvUljmQhB02HSqdNBhqKSg4/cf7l8Zo1ejvBUosrlgw3C3
apDaC4/xk7woFKVYW25teH2ze+Gpz/YsLDtmL7Bri8CGVsqsN9yqO8SstwKBa3Rt
xQ2em6XnnanApT4iFX4=
-----END CERTIFICATE----- -----END CERTIFICATE-----

View file

@ -1,42 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,3ACC7169D177F0159193ACAF3B3997A3
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
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,42 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-CBC,054A583F6C90570F
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
-----END RSA PRIVATE KEY-----

View file

@ -1,26 +1,27 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIEeDCCAuCgAwIBAgIUTqTcNqmr8Ou/MpL1AUnM/3gcoUkwDQYJKoZIhvcNAQEL MIIEkDCCAvigAwIBAgIBFDANBgkqhkiG9w0BAQsFADBKMQ8wDQYDVQQDEwZUZXN0
BQAwSjELMAkGA1UEBhMCREUxKjAoBgNVBAoTIUNTQUYgVG9vbHMgRGV2ZWxvcG1l ZXIxKjAoBgNVBAoTIUNTQUYgVG9vbHMgRGV2ZWxvcG1lbnQgKGludGVybmFsKTEL
bnQgKGludGVybmFsKTEPMA0GA1UEAxMGVGVzdGVyMCAXDTI1MTAxNzEwMjIzNloY MAkGA1UEBhMCREUwHhcNMjMwOTA0MDcyMjAzWhcNMjMxMDI0MDcyMjAzWjBVMRow
DzIxMjUwOTIzMTAyMjM2WjBKMQswCQYDVQQGEwJERTEqMCgGA1UEChMhQ1NBRiBU GAYDVQQDExFUTFMgVGVzdCBDbGllbnQgMTEqMCgGA1UEChMhQ1NBRiBUb29scyBE
b29scyBEZXZlbG9wbWVudCAoaW50ZXJuYWwpMQ8wDQYDVQQDEwZUZXN0ZXIwggGi ZXZlbG9wbWVudCAoaW50ZXJuYWwpMQswCQYDVQQGEwJERTCCAaIwDQYJKoZIhvcN
MA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDBN4fIBbwuGJXjXoa6F7e4Zzin AQEBBQADggGPADCCAYoCggGBAN0vZbLXtRzd61rR8Hos0BGnqCaJXIwGARwxJojM
Yd9EB4nt5TkNoMkRgQe0JIJ+t1/lS/xlI7ATxNjUdybnYwCrEfDvy8XGwN6te+Xh yxASFT+KeC4QDRkgRrK6OY4k/i7TEHuUGk/Bm754++554wmmhDqv1Q4+VhhR1K/J
dz6HKDWPijW+ritQW9kouxJJSpna95L8SqU4tjdfyL/2X9E/7j3VYw1//zcmhLJg Az/HVZNTAR1rPKwG82lyEpPxlRNZg/QtF9DqQSoSkL/fJLs+rq4zlKozXzREauZ5
1Os0+JHPcPuj1vmwLa1v7eGTCNlt0K8DbrlhPlteJB3hWolNIoVDjRemZFmqwUeV Be8So1dXRZfMVUMDgtk+IX8+iCeZisiWfv62ttQ0EiuiXLagd6ruEuoCSVi2tVsw
GZ/XJos7OTB07p08yCOFhLl9jXCgEDDkKmcnAil3YhjudlEGSjdzFLskVD4xrtQ5 sC/Hp8AI2Ro56mmHiWthuae1H8yDWUFLSe9AQW65qC/xVUgo/nMpK2BYVFKb70TM
GsbdJHyHhcUdgh+vqX2bFSklwdwVil1qIUEHnxpcRMaluZQ4u1tCgNhKNQHrJzVQ jl/dZM0Qn1tdiNyqCkbIhXjklZvZYhO+15TPkgDXDsqRUjpTrLZXLGrD6XIxCRLZ
n1aRVAYdX1PxfoIb5wt0+25MiVw8y8EcrMH97Ss26eNAtLeHZNrY9alqx/Cs8gOi GY6YrUfsFTjUC6JrUrAR8zY7SLsYN5sUmFUSMpJnI+T/SD4p/0CXrKrbMOjWQqz6
I8wA2Nga138tZuCJRXsDOnom9RrtdPLajhSb7n33Iq8ZDhYVGEIm2pc5MJxaI53V FX/WHPxvswGKHk5zHYGHrzx7OKmfVa6gzUgZSfOHj2xOOR2Un9DwNavIrmSCWYXK
e2WhmemFPfYwUAtzdGgwrBoY9MechdtNLGZqHxECAwEAAaNUMFIwDAYDVR0TAQH/ Zqig5qDyfzBvlXWEio/5GrDwgQIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1Ud
BAIwADATBgNVHSUEDDAKBggrBgEFBQcDAjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0O JQQMMAoGCCsGAQUFBwMCMA8GA1UdDwEB/wQFAwMHoAAwHQYDVR0OBBYEFKrFhODj
BBYEFBVaa/ovyPpbk/8nlmuISWB2/t8xMA0GCSqGSIb3DQEBCwUAA4IBgQC8EeDx TKCopb+WQa29PsHR4HXgMB8GA1UdIwQYMBaAFI6GhktAq9L2uRChC9LcXeedKiUg
qipM7bAFxkAOmvhNAjodKXRCWKhatD8HryeINOPgWajzLlHj/PCnULulhaFO1viA MA0GCSqGSIb3DQEBCwUAA4IBgQAbUDaIkmubooDde7BpZQx742BsPg4IN68bIg9A
+iBBKbHb+7LImb/owlNVu8iYDh/xBXmLrOHyd12K8dyN471iTBrskQwSCnYd6e/p 3jI9codx9c8l9ROvZ/7FeRNXzhYrQUwzcKpwtQ1mB7kM85oXaTLxrtnkZAO2fFSb
4i0hhNj5JidOgA6swjt9j4X7/IgsvXexLIAhqgQDSsKQpPK17E9IB+d5p3UHU71w 8RA6QjOrnOvewWaO3moCZaPnN1wWtlnUev2tD7D2Tz/f20dE2wbDV0BGb8bU4eGI
Ob1mGIZ2j/GJnC6YmGFPqIZZ+cy3aVOypWf8RVZYPTFCz43ZuC70cP3kl2io75Rp UVgzYrMh0MHaC8LKoXUWP97jp/p+9CG4D2S1CmpzP2Nm1dS03oj4UHIUtamjivYY
rWUNKXU+yUdBphHN6KJXUmlH4T9yqXKqnxK+9CnVC/CTlucF9VpktN7wfVxVPsrY vOeoKATXmj59lgYqqoAVbTH6f4mZlZGmzUhRxK6hck7xBdiXAwfta72m4WzE7HRh
L79iys+FLPKrDkqcjpIJ2l/n/ugcUcXvN477qFCGbRY/3tB3Dmf4AvMPpTsStkXw nHAgO5aVWb6zltvVDJhYumB9Itv+LI7uU8fF9Uyc65SZ2BevxgikoDNxTx0oNr+4
Ld+xAHog8upjVGsmXODX4sKjRMIFLIHbM01Iw0ECdKoKIMwjFGenwGmpBZA/Pfxe hExQhJfKuPFF2NI1N2tPYJT53Cek/ZJfjX3TyBneqehthtRqoAIIEaF/QlXqzJIi
AXBejd9KD0stCfHuKqx7Iu5N7Fg8BCLzmcSyoOmwJEo+Z3Z42IfSjOX8rQQ= G66YFC3xFlLmaQh52DJkF2+hzcPhFTVQv3yCirGLUSS9Nm7vTO2wnnW5arZazSV+
enRZb3oiVYFVDh0Hymz9g5VraMw=
-----END CERTIFICATE----- -----END CERTIFICATE-----

View file

@ -3,180 +3,180 @@ Public Key Info:
Key Security Level: High (3072 bits) Key Security Level: High (3072 bits)
modulus: modulus:
00:c1:37:87:c8:05:bc:2e:18:95:e3:5e:86:ba:17:b7 00:dd:2f:65:b2:d7:b5:1c:dd:eb:5a:d1:f0:7a:2c:d0
b8:67:38:a7:61:df:44:07:89:ed:e5:39:0d:a0:c9:11 11:a7:a8:26:89:5c:8c:06:01:1c:31:26:88:cc:cb:10
81:07:b4:24:82:7e:b7:5f:e5:4b:fc:65:23:b0:13:c4 12:15:3f:8a:78:2e:10:0d:19:20:46:b2:ba:39:8e:24
d8:d4:77:26:e7:63:00:ab:11:f0:ef:cb:c5:c6:c0:de fe:2e:d3:10:7b:94:1a:4f:c1:9b:be:78:fb:ee:79:e3
ad:7b:e5:e1:77:3e:87:28:35:8f:8a:35:be:ae:2b:50 09:a6:84:3a:af:d5:0e:3e:56:18:51:d4:af:c9:03:3f
5b:d9:28:bb:12:49:4a:99:da:f7:92:fc:4a:a5:38:b6 c7:55:93:53:01:1d:6b:3c:ac:06:f3:69:72:12:93:f1
37:5f:c8:bf:f6:5f:d1:3f:ee:3d:d5:63:0d:7f:ff:37 95:13:59:83:f4:2d:17:d0:ea:41:2a:12:90:bf:df:24
26:84:b2:60:d4:eb:34:f8:91:cf:70:fb:a3:d6:f9:b0 bb:3e:ae:ae:33:94:aa:33:5f:34:44:6a:e6:79:05:ef
2d:ad:6f:ed:e1:93:08:d9:6d:d0:af:03:6e:b9:61:3e 12:a3:57:57:45:97:cc:55:43:03:82:d9:3e:21:7f:3e
5b:5e:24:1d:e1:5a:89:4d:22:85:43:8d:17:a6:64:59 88:27:99:8a:c8:96:7e:fe:b6:b6:d4:34:12:2b:a2:5c
aa:c1:47:95:19:9f:d7:26:8b:3b:39:30:74:ee:9d:3c b6:a0:77:aa:ee:12:ea:02:49:58:b6:b5:5b:30:b0:2f
c8:23:85:84:b9:7d:8d:70:a0:10:30:e4:2a:67:27:02 c7:a7:c0:08:d9:1a:39:ea:69:87:89:6b:61:b9:a7:b5
29:77:62:18:ee:76:51:06:4a:37:73:14:bb:24:54:3e 1f:cc:83:59:41:4b:49:ef:40:41:6e:b9:a8:2f:f1:55
31:ae:d4:39:1a:c6:dd:24:7c:87:85:c5:1d:82:1f:af 48:28:fe:73:29:2b:60:58:54:52:9b:ef:44:cc:8e:5f
a9:7d:9b:15:29:25:c1:dc:15:8a:5d:6a:21:41:07:9f dd:64:cd:10:9f:5b:5d:88:dc:aa:0a:46:c8:85:78:e4
1a:5c:44:c6:a5:b9:94:38:bb:5b:42:80:d8:4a:35:01 95:9b:d9:62:13:be:d7:94:cf:92:00:d7:0e:ca:91:52
eb:27:35:50:9f:56:91:54:06:1d:5f:53:f1:7e:82:1b 3a:53:ac:b6:57:2c:6a:c3:e9:72:31:09:12:d9:19:8e
e7:0b:74:fb:6e:4c:89:5c:3c:cb:c1:1c:ac:c1:fd:ed 98:ad:47:ec:15:38:d4:0b:a2:6b:52:b0:11:f3:36:3b
2b:36:e9:e3:40:b4:b7:87:64:da:d8:f5:a9:6a:c7:f0 48:bb:18:37:9b:14:98:55:12:32:92:67:23:e4:ff:48
ac:f2:03:a2:23:cc:00:d8:d8:1a:d7:7f:2d:66:e0:89 3e:29:ff:40:97:ac:aa:db:30:e8:d6:42:ac:fa:15:7f
45:7b:03:3a:7a:26:f5:1a:ed:74:f2:da:8e:14:9b:ee d6:1c:fc:6f:b3:01:8a:1e:4e:73:1d:81:87:af:3c:7b
7d:f7:22:af:19:0e:16:15:18:42:26:da:97:39:30:9c 38:a9:9f:55:ae:a0:cd:48:19:49:f3:87:8f:6c:4e:39
5a:23:9d:d5:7b:65:a1:99:e9:85:3d:f6:30:50:0b:73 1d:94:9f:d0:f0:35:ab:c8:ae:64:82:59:85:ca:66:a8
74:68:30:ac:1a:18:f4:c7:9c:85:db:4d:2c:66:6a:1f a0:e6:a0:f2:7f:30:6f:95:75:84:8a:8f:f9:1a:b0:f0
11: 81:
public exponent: public exponent:
01:00:01: 01:00:01:
private exponent: private exponent:
70:0e:fd:af:d3:2b:ad:6c:52:d9:f8:43:99:00:12:6c 14:ff:c0:f9:ff:bc:b4:26:e5:87:53:d3:2e:e6:3e:42
5f:69:2b:22:87:33:54:4f:f9:69:fc:e9:db:7b:61:ac ce:d6:0a:02:94:84:be:b5:30:46:02:50:8e:90:e0:cf
7c:c4:4c:7c:66:73:81:a9:61:a5:73:1e:fc:8a:aa:9a b6:b0:b7:a6:bd:48:cc:d5:8b:d8:ea:72:ff:af:dd:17
ba:b6:94:18:94:81:99:b5:a1:0f:e2:15:c5:4c:ac:98 3c:be:d1:1b:ca:6d:cd:10:a6:86:a8:d9:d2:44:44:27
df:07:96:f8:ea:89:c6:97:31:b5:8d:b0:16:21:46:cc d0:65:51:65:0c:27:34:07:dc:7b:38:64:10:03:7c:f4
ce:28:62:3e:9b:c5:29:70:26:2f:d8:24:8e:a8:52:7d a1:cd:40:de:24:3a:e0:21:bc:ef:33:1d:9f:61:e8:57
d1:0e:83:ce:a7:09:9b:d3:57:87:3f:98:5f:c8:ab:ba ac:e4:9c:c0:7b:df:7c:f8:20:83:ac:0b:8e:0b:d3:62
aa:31:2e:19:ae:84:1d:39:ab:9e:b2:42:f6:75:ff:68 eb:8a:8e:03:5b:a3:e5:08:ae:df:a7:fe:85:92:e8:a5
ae:73:00:fa:d7:a4:c5:3d:7c:4f:54:65:4e:1c:88:e6 ae:58:46:72:d6:fc:91:43:b1:7b:a4:c0:5f:51:c3:50
c2:b5:9d:a2:ca:38:61:45:09:17:01:68:5a:f7:4e:4d 0d:e2:67:e8:af:51:13:41:a9:8d:ef:fb:a1:a4:e2:84
cb:24:f1:e3:57:a1:97:58:1e:b3:ef:57:91:e0:1d:95 7c:2b:a0:50:c5:fe:ed:84:a5:25:83:86:4a:d3:0f:56
51:8c:a9:4a:4e:f7:cd:fe:f7:04:f3:ff:67:ad:e7:01 37:38:e6:1e:26:7d:45:22:0b:ba:22:35:be:f8:8b:1b
14:dc:7e:e4:00:c0:38:51:2f:04:db:39:6c:f1:1b:a4 72:90:13:c4:1f:c5:d1:34:b5:0e:b2:ee:f7:e1:b9:5e
a5:f1:b4:5a:c3:17:d2:41:1a:5a:b5:f3:69:3b:b8:ba a2:29:8d:f9:6e:23:4b:50:8f:35:c8:a9:f3:d2:1f:dd
7b:59:96:d7:b2:c2:2c:9a:dd:e9:42:ce:fb:c8:22:fc ce:a0:96:50:2d:2e:af:cf:b5:e1:20:e7:e9:d2:49:ed
c5:33:97:6d:68:89:cd:e5:bc:2e:cc:9d:23:65:18:04 b5:0e:5b:3e:d1:4b:f1:fa:c2:73:3a:1b:51:34:7e:75
0c:83:b6:35:7e:16:09:96:d1:48:61:31:b1:ce:f8:50 30:06:d2:47:d2:a8:2a:45:be:16:fb:8f:63:84:85:b7
f0:14:ba:57:2f:02:1b:61:9c:bc:81:c1:ef:b3:bf:2f bf:f7:c4:c5:3d:95:56:8c:d1:02:7f:58:ac:4d:11:7b
fb:36:af:18:8c:90:40:55:5a:fd:a7:d4:ed:3b:94:a6 c5:55:f3:c8:4e:d7:d9:aa:62:b0:e3:1e:04:5c:97:d1
df:ab:eb:6c:d2:bc:e3:80:7e:d5:06:21:28:9b:04:65 ca:e2:71:aa:8b:33:b4:34:e9:04:d4:70:7c:f4:cb:57
b5:cc:04:b2:44:e9:2d:3b:7d:de:24:90:8d:fb:90:2d 19:c1:03:23:f4:bc:4d:91:8f:b2:9a:99:1c:6c:81:2d
40:17:51:cf:a7:fa:ee:54:89:8f:c0:f4:e4:c2:bd:44 4d:2d:e9:a1:e3:ce:e3:c9:62:52:89:1f:47:86:61:f1
94:1d:8d:fc:b7:d7:05:4d:46:dc:63:1f:7f:d8:b4:8b dd:bc:46:8d:79:0a:99:9d:aa:4b:a9:0a:72:54:db:dc
11:db:37:be:4d:e9:2b:33:b9:6b:8c:a7:f0:43:56:c5 ae:48:be:60:4a:73:99:d8:3c:9e:07:78:05:df:87:39
prime1: prime1:
00:f0:57:25:fd:aa:7e:98:13:08:28:99:16:eb:af:2e 00:e9:63:0f:d7:49:31:27:a8:36:fe:95:bd:8d:05:c1
22:f6:e6:d7:bd:df:49:57:17:71:bf:21:ba:bf:75:54 35:48:2e:03:4f:a6:57:54:3a:a4:95:3f:8e:9f:28:7c
5a:38:92:64:8c:4a:10:d4:4f:77:18:44:c2:79:f0:9d d2:df:af:54:36:9e:7c:9f:c3:b9:64:8f:c0:b0:96:3c
72:26:2e:9a:27:5d:e7:41:0b:c6:65:cb:fa:89:6d:9b aa:01:f6:9a:be:83:e2:85:20:0d:33:de:88:97:af:6f
fb:87:78:e2:87:22:d4:92:21:f5:3a:57:fa:b0:bf:bb be:3f:53:5a:a3:77:02:fd:81:17:91:3b:b2:2d:ab:78
66:a2:bf:43:af:e8:58:b4:e2:a1:ed:97:62:09:0d:49 db:d9:43:db:04:69:82:61:30:e4:96:ac:88:8b:f6:3f
ca:4c:99:a2:f4:f3:31:df:80:8e:56:be:64:9d:72:59 56:c4:49:fd:d5:e5:8c:9d:30:ad:cf:d9:8d:5c:87:b5
ef:e9:db:4d:a3:e2:cf:79:1e:99:89:b2:f1:e3:2d:bc 27:4b:09:8e:19:ed:e2:11:3f:69:b2:47:be:70:39:11
8f:a0:2a:2f:a6:f0:21:18:2d:f1:57:20:55:c1:c9:18 41:a3:db:bb:b9:0e:e4:7b:50:d0:d2:c2:89:81:36:b9
c1:64:c6:9c:00:df:b2:54:55:8d:fe:d3:46:a0:5c:2e 6b:a6:fe:94:5b:06:66:e6:ed:86:52:42:5e:a9:0e:18
f8:f7:10:b6:27:3a:4a:79:a1:14:b1:0c:c3:72:5b:2b db:18:f9:14:21:3d:e0:3c:8d:79:c3:f5:d2:cc:51:65
66:d6:85:2c:7e:58:72:eb:33:62:73:34:e5:38:87:2e fb:1c:49:ed:0a:d5:33:99:34:16:f9:1d:68:4a:78:da
17: 5f:
prime2: prime2:
00:cd:ce:5d:fb:04:16:34:f4:de:02:7d:00:07:3e:b0 00:f2:9d:ae:5f:bd:b7:a3:87:a7:8d:30:46:06:8b:15
94:8c:f4:3a:62:05:37:1a:4f:d8:40:2e:31:11:07:77 a9:e5:a9:58:1c:2b:3a:7e:78:35:36:56:31:42:df:46
09:8b:bd:76:6e:85:b9:43:df:3f:86:cb:db:6d:fe:c6 87:e8:57:0d:6e:99:de:cf:fb:a8:72:16:71:4b:b3:ad
4c:ca:e1:16:ce:5c:0e:e1:b1:10:0d:8d:48:99:d7:43 ed:74:07:cb:cf:7d:2b:12:89:66:c4:0f:8a:ea:e3:37
7f:6c:b6:20:b2:cd:0c:56:26:02:18:81:e1:67:e5:cd 17:2c:75:92:11:7a:a6:da:29:24:33:9b:69:c2:64:68
b3:66:1e:77:dc:49:6a:5d:8c:9c:0e:24:14:3e:a1:4a 03:db:31:de:fe:1d:a2:4d:9d:91:9f:f0:50:b8:8f:d0
7e:cf:72:e6:e4:03:e6:38:41:fa:2b:91:71:6c:33:b0 22:11:b9:b0:95:98:5e:65:bf:45:97:9b:35:f2:98:27
ec:07:3a:be:5b:f8:74:f5:e4:1f:9c:c4:d0:d4:75:a8 46:7c:b2:86:eb:7b:8b:57:f2:c3:49:47:7d:01:4a:9a
35:09:05:0f:7f:54:4e:2a:bc:cc:92:de:1e:f4:74:8a b0:e6:67:05:e5:61:7a:ab:63:c8:cb:d8:44:69:88:72
56:36:e0:b1:37:cf:b3:9c:57:05:76:59:69:c3:03:de a5:a9:60:89:60:df:e6:d9:4d:16:2b:35:7b:20:00:f3
c2:33:0c:c4:a1:4f:2a:b8:3c:20:63:c9:58:96:1a:e2 3c:d1:78:f9:22:eb:48:c3:7f:78:63:e6:34:60:48:30
62:ce:bf:fb:a9:51:b0:66:99:35:d6:d2:60:59:72:bd 66:02:bb:38:c2:94:2e:b9:86:b2:2f:9a:4f:17:7f:e1
17: 1f:
coefficient: coefficient:
33:6a:05:3e:1e:46:46:58:e2:61:38:6a:c2:8f:77:a2 00:93:3e:7c:b9:ea:87:52:37:fa:d5:0a:36:fb:e1:d0
27:b7:19:38:75:40:d6:8c:87:bc:65:a6:24:c3:97:e5 fc:62:4d:00:0b:ad:a8:fb:bd:34:53:96:c2:6c:a1:6a
ef:70:1b:2c:4e:9c:08:ca:1d:eb:97:11:74:14:bb:99 49:b7:a0:24:33:16:95:79:14:ac:bb:75:8d:78:e9:10
de:22:a1:6e:bc:6c:c6:25:98:8a:8e:17:f4:f9:4d:a3 fa:be:44:60:58:94:4a:9c:ba:64:1d:86:27:8b:7f:51
1d:01:5e:26:0e:b4:e8:1c:aa:06:7c:66:b1:89:5a:b4 4d:80:b0:ff:7a:91:c0:4d:a4:aa:d1:f1:79:7d:8f:71
82:65:d1:bf:20:cb:b2:57:a8:af:7f:00:07:00:7c:5e 49:12:73:d4:44:5f:0c:2e:55:a6:d9:13:b8:3b:e5:dc
d4:09:60:0c:0a:6e:a8:e1:16:1b:04:95:b1:bc:2b:35 e1:14:98:7e:eb:5b:60:ad:d7:4b:da:c0:d8:3f:bf:70
ad:80:78:0a:0a:1d:5f:c9:cc:24:3a:5e:20:03:50:44 92:53:8c:31:6a:8b:61:5e:a3:7d:ff:84:2c:7d:ed:9f
b8:b0:f3:f1:17:ff:41:b8:5d:56:9b:1c:f1:e6:2b:c6 74:29:9a:e7:14:fb:c3:ab:8e:9f:60:6a:98:ab:86:0b
ba:a2:8c:18:25:8c:d5:90:f1:28:66:29:bb:40:3d:b2 ea:fb:ff:20:2f:3b:a7:76:03:3a:55:bb:b2:c6:9c:b5
f9:65:99:2e:b7:1b:e3:d0:d2:1a:d7:96:70:cc:f6:74 66:36:b8:1c:7f:9b:b6:62:89:ff:6a:d6:35:58:0b:f0
c5:2e:bf:f5:c9:60:c0:ff:38:f8:a8:db:1a:7d:6a:4e 55:27:01:f0:67:8d:88:3f:74:48:3d:bf:8c:fc:05:62
47:
exp1: exp1:
5c:1b:49:f7:f9:0b:23:04:c8:2f:a6:db:dd:de:f8:f3 00:99:16:2d:91:dd:a4:ac:8a:9e:68:27:f8:89:c4:38
75:63:ea:72:5d:cc:21:90:5e:8b:3d:45:f0:71:ea:ad 93:a6:a0:e7:f3:1a:fd:35:76:b1:f6:64:16:3d:37:e5
d8:d8:61:a8:52:0a:39:13:6b:34:e5:c5:12:2e:60:68 88:bc:c8:d8:c8:6a:f4:fc:26:fa:38:88:42:b0:92:1b
8a:b1:79:6a:74:d6:57:5b:47:e1:63:56:d4:ac:29:07 80:b8:80:f5:c7:f9:e2:5f:c8:42:60:bf:9b:81:43:c6
30:57:e7:98:9a:84:94:ac:66:ea:c1:24:d5:ef:e4:c5 5c:58:55:68:a2:c8:b1:e1:6f:07:f2:6f:e1:d4:2b:21
e4:c1:20:13:9e:1b:c0:d6:c9:ef:e0:00:36:2f:dd:83 bf:b3:a7:da:c5:ee:1f:63:79:1a:b7:ea:bc:36:72:73
a5:ef:8b:40:0c:a3:a4:60:04:2c:c2:32:95:14:69:db e1:8a:27:ae:a4:db:49:7c:e2:2d:60:a5:27:20:86:b3
43:e8:43:cc:f6:f3:44:1b:b2:03:cf:8c:5b:df:ff:4f c0:ee:6b:7a:16:6f:ff:55:a8:ee:bf:ce:67:90:5d:1e
9b:b6:0f:25:0f:09:df:d6:5b:93:64:54:f9:3b:34:3d 80:9b:e6:ca:1f:fd:30:c9:e2:9c:d7:62:5b:a7:b2:29
89:7d:83:f3:e1:c6:da:03:1f:b3:f5:0c:30:10:a3:ff b5:ff:78:06:00:1f:16:e8:6a:ed:2c:8f:f4:5f:97:ab
cd:cf:9d:bf:52:db:8f:d9:67:b0:a2:8f:94:97:d3:fe 9e:2b:a7:56:18:e7:e9:6a:4e:b2:8c:63:76:be:26:b6
49:60:28:39:13:74:97:26:ce:28:10:b1:78:04:76:69 6a:1c:88:31:40:65:d0:ce:b1:68:50:47:85:dd:33:a0
a9:
exp2: exp2:
6e:6d:c5:d5:b3:8a:aa:dd:9c:e6:5e:e6:0d:fd:20:48 00:8d:b1:5f:7c:94:ed:62:39:40:b6:a9:a1:cc:02:80
85:1d:62:da:47:8c:1a:8d:2f:2e:b8:da:51:15:dd:54 c5:77:d6:9e:19:dd:79:4d:11:61:6a:79:8e:4d:92:de
7c:eb:ab:49:80:6d:39:32:e7:e6:4f:2a:2d:6a:20:43 bb:53:0b:3c:52:02:d5:69:3c:7d:95:1b:dc:51:2d:00
02:35:26:c4:91:76:d6:b8:e8:31:2d:57:00:5d:15:f5 00:35:0a:b4:92:5a:74:c4:5f:b0:c0:02:9f:cc:2c:a5
a0:82:55:27:3b:88:dc:0c:c6:e1:19:87:b5:f5:03:9b 29:08:93:25:9a:c5:ba:1a:a1:7a:7e:15:5e:ff:e3:ea
b8:36:ae:ff:bf:50:d8:63:63:34:df:3d:11:a1:ff:d3 07:8e:85:a2:c9:60:7f:40:bb:2c:a8:6f:0e:85:ab:a0
ed:41:ed:0b:f9:df:a4:de:19:fb:18:ae:70:6d:88:08 0f:b5:b0:70:1b:fe:1f:eb:66:78:fb:60:ef:71:de:40
0d:95:02:a1:5c:be:7d:55:eb:74:75:d2:cb:bd:5a:05 d9:de:cb:d9:16:40:52:12:2c:3a:b7:5a:63:fc:54:18
23:12:d9:0e:ec:50:88:f4:07:1c:e3:1c:5e:f4:cd:69 e2:05:bd:d7:68:ae:b4:98:d2:2f:1c:36:13:46:5b:25
97:46:97:30:a8:3c:ea:ad:72:db:de:fc:35:cc:b4:d1 31:f1:28:eb:32:c3:b1:2b:e9:e4:6f:99:cd:6d:d4:80
25:0d:3b:d0:86:27:18:f6:02:37:28:c9:64:b9:86:31 3a:5d:d0:3c:18:93:b7:2c:4e:0e:fe:b1:1c:97:ba:b1
98:58:41:13:c8:26:4b:d6:f7:a1:8d:fe:6e:e0:76:ff 61:72:68:eb:6e:60:62:a5:81:b0:21:33:0a:cc:1b:a8
5b:
Public Key PIN: Public Key PIN:
pin-sha256:Zv2mSFRUYM7ofg5obMJJxhZpnuvO7gkCOlqfDK1gzks= pin-sha256:iFdBnKP/7hZCLdj7qqTtdNPFjpZGka259fSYvv3X02U=
Public Key ID: Public Key ID:
sha256:66fda648545460cee87e0e686cc249c616699eebceee09023a5a9f0cad60ce4b sha256:8857419ca3ffee16422dd8fbaaa4ed74d3c58e964691adb9f5f498befdd7d365
sha1:155a6bfa2fc8fa5b93ff27966b88496076fedf31 sha1:aac584e0e34ca0a8a5bf9641adbd3ec1d1e075e0
-----BEGIN RSA PRIVATE KEY----- -----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY----- -----END RSA PRIVATE KEY-----

View file

@ -1,37 +0,0 @@
// This file is Free Software under the Apache-2.0 License
// without warranty, see README.md and LICENSES/Apache-2.0.txt for details.
//
// SPDX-License-Identifier: Apache-2.0
//
// SPDX-FileCopyrightText: 2025 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
// Software-Engineering: 2025 Intevation GmbH <https://intevation.de>
package misc
import (
"encoding/json"
"fmt"
"io"
)
// StrictJSONParse creates a JSON decoder that decodes an interface
// while not allowing trailing data
func StrictJSONParse(jsonData io.Reader, target any) error {
decoder := json.NewDecoder(jsonData)
// Don't allow unknown fields
decoder.DisallowUnknownFields()
if err := decoder.Decode(target); err != nil {
return fmt.Errorf("JSON decoding error: %w", err)
}
// Check for any trailing data after the main JSON structure
if _, err := decoder.Token(); err != io.EOF {
if err != nil {
return fmt.Errorf("error reading trailing data: %w", err)
}
return fmt.Errorf("unexpected trailing data after JSON object")
}
return nil
}

View file

@ -6,7 +6,7 @@
// SPDX-FileCopyrightText: 2023 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de> // SPDX-FileCopyrightText: 2023 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
// Software-Engineering: 2023 Intevation GmbH <https://intevation.de> // Software-Engineering: 2023 Intevation GmbH <https://intevation.de>
package misc //revive:disable-line:var-naming package misc
import ( import (
"fmt" "fmt"

View file

@ -1,21 +0,0 @@
// This file is Free Software under the Apache-2.0 License
// without warranty, see README.md and LICENSES/Apache-2.0.txt for details.
//
// SPDX-License-Identifier: Apache-2.0
//
// SPDX-FileCopyrightText: 2025 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
// Software-Engineering: 2025 Intevation GmbH <https://intevation.de>
package misc
import "net/url"
// JoinURL joins the two URLs while preserving the query and fragment part of the latter.
func JoinURL(baseURL *url.URL, relativeURL *url.URL) *url.URL {
u := baseURL.JoinPath(relativeURL.Path)
u.RawQuery = relativeURL.RawQuery
u.RawFragment = relativeURL.RawFragment
// Enforce https, this is required if the base url was only a domain
u.Scheme = "https"
return u
}

View file

@ -81,7 +81,7 @@ func TestUnmarshalText(t *testing.T) {
byteSlice := []byte{'3', 'h'} byteSlice := []byte{'3', 'h'}
var emptySlice []byte var emptySlice []byte
if testTimeRange.UnmarshalText(byteSlice) != nil { if testTimeRange.UnmarshalText(byteSlice) != nil {
t.Error(testTimeRange.UnmarshalText(byteSlice).Error()) t.Errorf(testTimeRange.UnmarshalText(byteSlice).Error())
} }
if testTimeRange.UnmarshalText(emptySlice) == nil { if testTimeRange.UnmarshalText(emptySlice) == nil {
t.Errorf("Failure: UnmarshalText succeeded on invalid slice of bytes.") t.Errorf("Failure: UnmarshalText succeeded on invalid slice of bytes.")
@ -104,10 +104,10 @@ func TestUnmarshalFlag(t *testing.T) {
time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)) time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC))
if err := testTimeRange.UnmarshalFlag("3h"); err != nil { if err := testTimeRange.UnmarshalFlag("3h"); err != nil {
t.Error(err.Error()) t.Errorf(err.Error())
} }
if err := testTimeRange.UnmarshalFlag("2006-01-02T15:04:05"); err != nil { if err := testTimeRange.UnmarshalFlag("2006-01-02T15:04:05"); err != nil {
t.Error(err.Error()) t.Errorf(err.Error())
} }
if err := testTimeRange.UnmarshalFlag("2006-01-02T15:04:05a"); err == nil { if err := testTimeRange.UnmarshalFlag("2006-01-02T15:04:05a"); err == nil {
t.Errorf("Failure: Extracted time from invalid string") t.Errorf("Failure: Extracted time from invalid string")
@ -119,7 +119,7 @@ func TestUnmarshalFlag(t *testing.T) {
t.Errorf("Failure: Extracted time from invalid string") t.Errorf("Failure: Extracted time from invalid string")
} }
if err := testTimeRange.UnmarshalFlag("2006-01-02T15:04:05, 2007-01-02T15:04:05"); err != nil { if err := testTimeRange.UnmarshalFlag("2006-01-02T15:04:05, 2007-01-02T15:04:05"); err != nil {
t.Error(err.Error()) t.Errorf(err.Error())
} }
} }

View file

@ -46,6 +46,7 @@ type Parser[C any] struct {
// If a config file was specified it is loaded. // If a config file was specified it is loaded.
// Returns the arguments and the configuration. // Returns the arguments and the configuration.
func (p *Parser[C]) Parse() ([]string, *C, error) { func (p *Parser[C]) Parse() ([]string, *C, error) {
var cmdLineOpts C var cmdLineOpts C
if p.SetDefaults != nil { if p.SetDefaults != nil {
p.SetDefaults(&cmdLineOpts) p.SetDefaults(&cmdLineOpts)
@ -81,7 +82,6 @@ func (p *Parser[C]) Parse() ([]string, *C, error) {
// No config file -> We are good. // No config file -> We are good.
if path == "" { if path == "" {
slog.Warn("No config file found. Maybe you want to specify one or store it in a respective default location", "locations", p.DefaultConfigLocations)
return args, &cmdLineOpts, nil return args, &cmdLineOpts, nil
} }

View file

@ -90,7 +90,7 @@ func TestParse(t *testing.T) {
cmd.Env = append(os.Environ(), "TEST_HELP=1") cmd.Env = append(os.Environ(), "TEST_HELP=1")
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf(err.Error())
} }
// test the version flag // test the version flag
@ -104,7 +104,7 @@ func TestParse(t *testing.T) {
cmd.Env = append(os.Environ(), "TEST_VERSION=1") cmd.Env = append(os.Environ(), "TEST_VERSION=1")
err = cmd.Run() err = cmd.Run()
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf(err.Error())
} }
} }
@ -140,7 +140,7 @@ func TestLoadToml(t *testing.T) {
t.Errorf("Failure: Succeeded in parsing nonexistant parameter") t.Errorf("Failure: Succeeded in parsing nonexistant parameter")
} }
if err := loadTOML(&cfg, "data/config.toml"); err != nil { if err := loadTOML(&cfg, "data/config.toml"); err != nil {
t.Error(err.Error()) t.Errorf(err.Error())
} }
} }

View file

@ -1,171 +0,0 @@
{
"document": {
"category": "csaf_vex",
"csaf_version": "2.0",
"distribution": {
"tlp": {
"label": "WHITE",
"url": "https://www.first.org/tlp/v1/"
}
},
"notes": [
{
"category": "summary",
"title": "Test document summary",
"text": "Auto generated test CSAF document"
}
],
"publisher": {
"category": "vendor",
"name": "ACME Inc.",
"namespace": "https://www.example.com"
},
"title": "Test CSAF document",
"tracking": {
"current_release_date": "2020-01-01T00:00:00Z",
"generator": {
"date": "2020-01-01T00:00:00Z",
"engine": {
"name": "csaf-tool",
"version": "0.3.2"
}
},
"id": "Avendor-advisory-0004",
"initial_release_date": "2020-01-01T00:00:00Z",
"revision_history": [
{
"date": "2020-01-01T00:00:00Z",
"number": "1",
"summary": "Initial version"
}
],
"status": "final",
"version": "1"
}
},
"product_tree": {
"branches": [
{
"category": "vendor",
"name": "AVendor",
"branches": [
{
"category": "product_name",
"name": "product_1",
"branches": [
{
"category": "product_version",
"name": "1.1",
"product": {
"name": "AVendor product_1 1.1",
"product_id": "CSAFPID_0001"
}
},
{
"category": "product_version",
"name": "1.2",
"product": {
"name": "AVendor product_1 1.2",
"product_id": "CSAFPID_0002"
}
},
{
"category": "product_version",
"name": "2.0",
"product": {
"name": "AVendor product_1 2.0",
"product_id": "CSAFPID_0003"
}
}
]
}
]
},
{
"category": "vendor",
"name": "AVendor1",
"branches": [
{
"category": "product_name",
"name": "product_2",
"branches": [
{
"category": "product_version",
"name": "1",
"product": {
"name": "AVendor1 product_2 1",
"product_id": "CSAFPID_0004"
}
}
]
}
]
},
{
"category": "vendor",
"name": "AVendor",
"branches": [
{
"category": "product_name",
"name": "product_3",
"branches": [
{
"category": "product_version",
"name": "2022H2",
"product": {
"name": "AVendor product_3 2022H2",
"product_id": "CSAFPID_0005"
}
}
]
}
]
}
]
},
"vulnerabilities": [
{
"cve": "CVE-2020-1234",
"notes": [
{
"category": "description",
"title": "CVE description",
"text": "https://nvd.nist.gov/vuln/detail/CVE-2020-1234"
}
],
"product_status": {
"under_investigation": ["CSAFPID_0001"]
},
"threats": [
{
"category": "impact",
"details": "Customers should upgrade to the latest version of the product",
"date": "2020-01-01T00:00:00Z",
"product_ids": ["CSAFPID_0001"]
}
]
},
{
"cve": "CVE-2020-9876",
"notes": [
{
"category": "description",
"title": "CVE description",
"text": "https://nvd.nist.gov/vuln/detail/CVE-2020-9876"
}
],
"product_status": {
"under_investigation": ["CSAFPID_0001"]
},
"threats": [
{
"category": "impact",
"details": "Still under investigation",
"date": "2020-01-01T00:00:00Z",
"product_ids": ["CSAFPID_0001"]
}
]
}
]
}
invalid data

View file

@ -1,169 +0,0 @@
{
"document": {
"category": "csaf_vex",
"csaf_version": "2.0",
"distribution": {
"tlp": {
"label": "WHITE",
"url": "https://www.first.org/tlp/v1/"
}
},
"notes": [
{
"category": "summary",
"title": "Test document summary",
"text": "Auto generated test CSAF document"
}
],
"publisher": {
"category": "vendor",
"name": "ACME Inc.",
"namespace": "https://www.example.com"
},
"title": "Test CSAF document",
"tracking": {
"current_release_date": "2020-01-01T00:00:00Z",
"generator": {
"date": "2020-01-01T00:00:00Z",
"engine": {
"name": "csaf-tool"
}
},
"id": "Avendor-advisory-0004",
"initial_release_date": "2020-01-01T00:00:00Z",
"revision_history": [
{
"date": "2020-01-01T00:00:00Z",
"number": "1",
"summary": "Initial version"
}
],
"status": "final",
"version": "1"
}
},
"product_tree": {
"branches": [
{
"category": "vendor",
"name": "AVendor",
"branches": [
{
"category": "product_name",
"name": "product_1",
"branches": [
{
"category": "product_version",
"name": "1.1",
"product": {
"name": "AVendor product_1 1.1",
"product_id": "CSAFPID_0001"
}
},
{
"category": "product_version",
"name": "1.2",
"product": {
"name": "AVendor product_1 1.2",
"product_id": "CSAFPID_0002"
}
},
{
"category": "product_version",
"name": "2.0",
"product": {
"name": "AVendor product_1 2.0",
"product_id": "CSAFPID_0003"
}
}
]
}
]
},
{
"category": "vendor",
"name": "AVendor1",
"branches": [
{
"category": "product_name",
"name": "product_2",
"branches": [
{
"category": "product_version",
"name": "1",
"product": {
"name": "AVendor1 product_2 1",
"product_id": "CSAFPID_0004"
}
}
]
}
]
},
{
"category": "vendor",
"name": "AVendor",
"branches": [
{
"category": "product_name",
"name": "product_3",
"branches": [
{
"category": "product_version",
"name": "2022H2",
"product": {
"name": "AVendor product_3 2022H2",
"product_id": "CSAFPID_0005"
}
}
]
}
]
}
]
},
"vulnerabilities": [
{
"cve": "CVE-2020-1234",
"notes": [
{
"category": "description",
"title": "CVE description",
"text": "https://nvd.nist.gov/vuln/detail/CVE-2020-1234"
}
],
"product_status": {
"under_investigation": ["CSAFPID_0001"]
},
"threats": [
{
"category": "impact",
"details": "Customers should upgrade to the latest version of the product",
"date": "2020-01-01T00:00:00Z",
"product_ids": ["CSAFPID_0001"]
}
]
},
{
"cve": "CVE-2020-9876",
"notes": [
{
"category": "description",
"title": "CVE description",
"text": "https://nvd.nist.gov/vuln/detail/CVE-2020-9876"
}
],
"product_status": {
"under_investigation": ["CSAFPID_0001"]
},
"threats": [
{
"category": "impact",
"details": "Still under investigation",
"date": "2020-01-01T00:00:00Z",
"product_ids": ["CSAFPID_0001"]
}
]
}
]
}

View file

@ -1,170 +0,0 @@
{
"document": {
"category": "csaf_vex",
"csaf_version": "2.0",
"distribution": {
"tlp": {
"label": "WHITE",
"url": "https://www.first.org/tlp/v1/"
}
},
"notes": [
{
"category": "summary",
"title": "Test document summary",
"text": "Auto generated test CSAF document"
}
],
"publisher": {
"category": "vendor",
"name": "ACME Inc.",
"namespace": "https://www.example.com"
},
"title": "Test CSAF document",
"tracking": {
"current_release_date": "2020-01-01T00:00:00Z",
"generator": {
"date": "2020-01-01T00:00:00Z",
"engine": {
"name": "csaf-tool",
"version": "0.3.2"
}
},
"id": "Avendor-advisory-0004",
"initial_release_date": "2020-01-01T00:00:00Z",
"revision_history": [
{
"date": "2020-01-01T00:00:00Z",
"number": "1",
"summary": "Initial version"
}
],
"status": "final",
"version": "1"
}
},
"product_tree": {
"branches": [
{
"category": "vendor",
"name": "AVendor",
"branches": [
{
"category": "product_name",
"name": "product_1",
"branches": [
{
"category": "product_version",
"name": "1.1",
"product": {
"name": "AVendor product_1 1.1",
"product_id": "CSAFPID_0001"
}
},
{
"category": "product_version",
"name": "1.2",
"product": {
"name": "AVendor product_1 1.2",
"product_id": "CSAFPID_0002"
}
},
{
"category": "product_version",
"name": "2.0",
"product": {
"name": "AVendor product_1 2.0",
"product_id": "CSAFPID_0003"
}
}
]
}
]
},
{
"category": "vendor",
"name": "AVendor1",
"branches": [
{
"category": "product_name",
"name": "product_2",
"branches": [
{
"category": "product_version",
"name": "1",
"product": {
"name": "AVendor1 product_2 1",
"product_id": "CSAFPID_0004"
}
}
]
}
]
},
{
"category": "vendor",
"name": "AVendor",
"branches": [
{
"category": "product_name",
"name": "product_3",
"branches": [
{
"category": "product_version",
"name": "2022H2",
"product": {
"name": "AVendor product_3 2022H2",
"product_id": "CSAFPID_0005"
}
}
]
}
]
}
]
},
"vulnerabilities": [
{
"cve": "CVE-2020-1234",
"notes": [
{
"category": "description",
"title": "CVE description",
"text": "https://nvd.nist.gov/vuln/detail/CVE-2020-1234"
}
],
"product_status": {
"under_investigation": ["CSAFPID_0001"]
},
"threats": [
{
"category": "impact",
"details": "Customers should upgrade to the latest version of the product",
"date": "2020-01-01T00:00:00Z",
"product_ids": ["CSAFPID_0001"]
}
]
},
{
"cve": "CVE-2020-9876",
"notes": [
{
"category": "description",
"title": "CVE description",
"text": "https://nvd.nist.gov/vuln/detail/CVE-2020-9876"
}
],
"product_status": {
"under_investigation": ["CSAFPID_0001"]
},
"threats": [
{
"category": "impact",
"details": "Still under investigation",
"date": "2020-01-01T00:00:00Z",
"product_ids": ["CSAFPID_0001"]
}
]
}
]
}

View file

@ -6,7 +6,7 @@
// SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de> // SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
// Software-Engineering: 2022 Intevation GmbH <https://intevation.de> // Software-Engineering: 2022 Intevation GmbH <https://intevation.de>
package util //revive:disable-line:var-naming package util
import ( import (
"context" "context"

View file

@ -6,7 +6,7 @@
// SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de> // SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
// Software-Engineering: 2022 Intevation GmbH <https://intevation.de> // Software-Engineering: 2022 Intevation GmbH <https://intevation.de>
package util //revive:disable-line:var-naming package util
import ( import (
"bufio" "bufio"

View file

@ -6,7 +6,7 @@
// SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de> // SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
// Software-Engineering: 2022 Intevation GmbH <https://intevation.de> // Software-Engineering: 2022 Intevation GmbH <https://intevation.de>
package util //revive:disable-line:var-naming package util
import ( import (
"bytes" "bytes"

View file

@ -6,7 +6,7 @@
// SPDX-FileCopyrightText: 2023 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de> // SPDX-FileCopyrightText: 2023 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
// Software-Engineering: 2023 Intevation GmbH <https://intevation.de> // Software-Engineering: 2023 Intevation GmbH <https://intevation.de>
package util //revive:disable-line:var-naming package util
// Set is a simple set type. // Set is a simple set type.
type Set[K comparable] map[K]struct{} type Set[K comparable] map[K]struct{}

View file

@ -6,7 +6,7 @@
// SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de> // SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
// Software-Engineering: 2022 Intevation GmbH <https://intevation.de> // Software-Engineering: 2022 Intevation GmbH <https://intevation.de>
package util //revive:disable-line:var-naming package util
import ( import (
"net/url" "net/url"