mirror of
https://github.com/gocsaf/csaf.git
synced 2025-12-22 11:55:40 +01:00
Compare commits
87 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
586524a97e | ||
|
|
52ce6bcde6 | ||
|
|
9393271699 | ||
|
|
0630a9a64a | ||
|
|
502376ce3a | ||
|
|
c678a97d43 | ||
|
|
9a37a8ecfa | ||
|
|
d6bac95e45 | ||
|
|
5a1c2a0873 | ||
|
|
8dd4cb4fa8 | ||
|
|
9607f8db94 | ||
|
|
46118544be | ||
|
|
fb59a40609 | ||
|
|
cf9c62fcc0 | ||
|
|
b6281012f5 | ||
|
|
8740244dd8 | ||
|
|
6cc1d7a38f | ||
|
|
ffb1a31944 | ||
|
|
ef44c92f8b | ||
|
|
223570ac9b | ||
|
|
fc012fa820 | ||
|
|
f046ade489 | ||
|
|
c6bad42c24 | ||
|
|
05eae0a9ae | ||
|
|
e3d2a58528 | ||
|
|
04955d6fad | ||
|
|
0dbf822cbd | ||
|
|
bcb7c8be10 | ||
|
|
5c1b061255 | ||
|
|
d1f33ab27d | ||
|
|
187d114631 | ||
|
|
1a2a8fae9c | ||
|
|
f6927154bf | ||
|
|
1f1a2a4cbc | ||
|
|
fa8370bd60 | ||
|
|
7ab964a3e3 | ||
|
|
c7a284bf7f | ||
|
|
08ab318545 | ||
|
|
a2fab16d3b | ||
|
|
108e5f8620 | ||
|
|
100e4d395b | ||
|
|
7fc5600521 | ||
|
|
7f27a63e3c | ||
|
|
230e9f2d2b | ||
|
|
ae184eb189 | ||
|
|
4b4d6ed594 | ||
|
|
7935818600 | ||
|
|
c81f55a752 | ||
|
|
e7c08d05cd | ||
|
|
fc3837d655 | ||
|
|
dad4e54184 | ||
|
|
01c43d96ce | ||
|
|
ca54ba53be | ||
|
|
3262e2ec2a | ||
|
|
bcd34d9fba | ||
|
|
5fd5076f52 | ||
|
|
21ce19735b | ||
|
|
27e9519ed5 | ||
|
|
a7b1291be8 | ||
|
|
7b7d0c4dcb | ||
|
|
a6d0a0c790 | ||
|
|
d54e211ef3 | ||
|
|
c833c00f84 | ||
|
|
4066704c1a | ||
|
|
f154b78340 | ||
|
|
d5778f0755 | ||
|
|
5d37dd1339 | ||
|
|
d09db6635d | ||
|
|
3f4fe5cf18 | ||
|
|
02d4931152 | ||
|
|
9c62e89a23 | ||
|
|
062e145761 | ||
|
|
36aab33de4 | ||
|
|
1098c6add0 | ||
|
|
091854a248 | ||
|
|
ce886f138a | ||
|
|
6ac97810d0 | ||
|
|
cb291bb81b | ||
|
|
12cde3aa3c | ||
|
|
fa1861385a | ||
|
|
dcdbc5d49d | ||
|
|
34705f3c6e | ||
|
|
6955c4e37c | ||
|
|
fc64bf7165 | ||
|
|
161ec1f15c | ||
|
|
3ab00e8759 | ||
|
|
91b5b4543e |
56 changed files with 1399 additions and 575 deletions
4
.github/workflows/generate-markdown.yml
vendored
4
.github/workflows/generate-markdown.yml
vendored
|
|
@ -13,8 +13,8 @@ jobs:
|
||||||
auto-update-readme:
|
auto-update-readme:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v5
|
||||||
- name: Markdown autodocs
|
- name: Markdown autodocs
|
||||||
uses: dineshsonachalam/markdown-autodocs@v1.0.4
|
uses: dineshsonachalam/markdown-autodocs@v1.0.7
|
||||||
with:
|
with:
|
||||||
output_file_paths: '[./README.md, ./docs/*.md]'
|
output_file_paths: '[./README.md, ./docs/*.md]'
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
name: Go
|
name: Go Test (oldstable)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
|
@ -12,10 +12,10 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: 'oldstable'
|
go-version: 'oldstable'
|
||||||
|
|
||||||
36
.github/workflows/go.yml
vendored
36
.github/workflows/go.yml
vendored
|
|
@ -12,10 +12,11 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: "stable"
|
go-version: "stable"
|
||||||
|
|
||||||
|
|
@ -26,15 +27,36 @@ jobs:
|
||||||
run: go vet ./...
|
run: go vet ./...
|
||||||
|
|
||||||
- name: gofmt
|
- name: gofmt
|
||||||
uses: Jerome1337/gofmt-action@v1.0.4
|
uses: Jerome1337/gofmt-action@v1.0.5
|
||||||
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.7.4
|
uses: morphy2k/revive-action@v2
|
||||||
|
|
||||||
- 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 }}
|
||||||
|
|
|
||||||
14
.github/workflows/itest.yml
vendored
14
.github/workflows/itest.yml
vendored
|
|
@ -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@v5
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: '^1.23.6'
|
go-version-file: "go.mod"
|
||||||
|
check-latest: true
|
||||||
|
|
||||||
- name: Set up Node.js
|
- name: Set up Node.js
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 24
|
||||||
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Execute the scripts
|
- name: Execute the scripts
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
|
|
@ -7,17 +7,19 @@ 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@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: '^1.23.6'
|
go-version: '^1.24.9'
|
||||||
|
check-latest: true
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: make dist
|
run: make dist
|
||||||
|
|
|
||||||
62
Makefile
62
Makefile
|
|
@ -12,15 +12,15 @@ SHELL = /bin/bash
|
||||||
BUILD = go build
|
BUILD = go build
|
||||||
MKDIR = mkdir -p
|
MKDIR = mkdir -p
|
||||||
|
|
||||||
.PHONY: build build_linux build_win build_mac_amd64 build_mac_arm64 tag_checked_out mostlyclean
|
.PHONY: build build_linux build_linux_arm64 build_win build_win_arm64 build_mac_amd64 build_mac_arm64 tag_checked_out mostlyclean
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@echo choose a target from: build build_linux build_win build_mac_amd64 build_mac_arm64 mostlyclean
|
@echo choose a target from: build build_linux build_linux_arm64 build_win build_win_arm64 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_win build_mac_amd64 build_mac_arm64
|
build: build_linux build_linux_arm64 build_win build_win_arm64 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_win build_mac_amd64 build_mac_arm64: tag_checked_out
|
build_linux build_linux_arm64 build_win build_win_arm64 build_mac_amd64 build_mac_arm64: tag_checked_out
|
||||||
endif
|
endif
|
||||||
|
|
||||||
tag_checked_out:
|
tag_checked_out:
|
||||||
|
|
@ -47,13 +47,18 @@ 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)
|
GITDESC := $(shell git describe --tags --always --dirty=-modified 2>/dev/null || true)
|
||||||
|
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)\'
|
||||||
|
|
||||||
|
|
@ -64,31 +69,49 @@ 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
|
||||||
|
|
||||||
GOARCH = amd64
|
build_linux: GOOS=linux
|
||||||
build_linux: GOOS = linux
|
build_linux: GOARCH=amd64
|
||||||
build_win: GOOS = windows
|
|
||||||
build_mac_amd64: GOOS = darwin
|
|
||||||
|
|
||||||
build_mac_arm64: GOARCH = arm64
|
build_win: GOOS=windows
|
||||||
build_mac_arm64: GOOS = darwin
|
build_win: GOARCH=amd64
|
||||||
|
|
||||||
build_linux build_win build_mac_amd64 build_mac_arm64:
|
build_mac_amd64: GOOS=darwin
|
||||||
|
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_win build_mac_amd64 build_mac_arm64
|
dist: build_linux build_linux_arm64 build_win build_win_arm64 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
|
||||||
|
|
@ -98,9 +121,20 @@ dist: build_linux build_win build_mac_amd64 build_mac_arm64
|
||||||
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
|
||||||
cp -r README.md docs bin-linux-amd64 dist/$(DISTDIR)-gnulinux-amd64
|
mkdir dist/$(DISTDIR)-gnulinux-arm64
|
||||||
|
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
|
||||||
|
|
|
||||||
36
README.md
36
README.md
|
|
@ -9,14 +9,6 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|
||||||
> [!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
|
||||||
|
|
||||||
|
|
@ -49,13 +41,20 @@ 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`
|
are small examples of how to use `github.com/gocsaf/csaf` as an API. Currently this is a work in progress.
|
||||||
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
|
||||||
|
|
@ -79,7 +78,8 @@ Download the binaries from the most recent release assets on Github.
|
||||||
|
|
||||||
### Build from sources
|
### Build from sources
|
||||||
|
|
||||||
- A recent version of **Go** (1.23+) should be installed. [Go installation](https://go.dev/doc/install)
|
- Needs a [supported version](docs/Development.md) of **Go** to be installed.
|
||||||
|
[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,6 +107,14 @@ 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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
@ -25,6 +24,7 @@ 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 json.NewDecoder(tee).Decode(&doc)
|
return misc.StrictJSONParse(tee, &doc)
|
||||||
}(); err != nil {
|
}(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
|
@ -31,6 +30,7 @@ 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]{}
|
||||||
|
|
||||||
base, err := url.Parse(w.loc)
|
pmdURL, 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,
|
||||||
base)
|
pmdURL)
|
||||||
|
|
||||||
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 json.NewDecoder(tee).Decode(&advisory)
|
return misc.StrictJSONParse(tee, &advisory)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := downloadJSON(w.client, file.URL(), download); err != nil {
|
if err := downloadJSON(w.client, file.URL(), download); err != nil {
|
||||||
|
|
@ -627,7 +627,6 @@ 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)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ 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"
|
||||||
|
|
@ -93,7 +95,12 @@ func (pgs pages) listed(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Links may be relative
|
// Links may be relative
|
||||||
abs := baseURL.ResolveReference(u).String()
|
var abs 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
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
@ -29,6 +28,8 @@ 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"
|
||||||
|
|
||||||
|
|
@ -251,14 +252,14 @@ func (p *processor) run(domains []string) (*Report, error) {
|
||||||
p.reset()
|
p.reset()
|
||||||
|
|
||||||
if !p.checkProviderMetadata(d) {
|
if !p.checkProviderMetadata(d) {
|
||||||
// We cannot build a report if the provider metadata cannot be parsed.
|
// We need to fail the domain if the PMD cannot be parsed.
|
||||||
log.Printf("Could not parse the Provider-Metadata.json of: %s\n", d)
|
p.badProviderMetadata.use()
|
||||||
continue
|
p.badProviderMetadata.error("Could not parse the Provider-Metadata.json of: %s", d)
|
||||||
|
|
||||||
}
|
}
|
||||||
if err := p.checkDomain(d); err != nil {
|
if err := p.checkDomain(d); err != nil {
|
||||||
log.Printf("Failed to find valid provider-metadata.json for domain %s: %v. "+
|
p.badProviderMetadata.use()
|
||||||
"Continuing with next domain.", d, err)
|
p.badProviderMetadata.error("Failed to find valid provider-metadata.json for domain %s: %v. ", d, err)
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
domain := &Domain{Name: d}
|
domain := &Domain{Name: d}
|
||||||
|
|
||||||
|
|
@ -269,8 +270,10 @@ func (p *processor) run(domains []string) (*Report, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if domain.Role == nil {
|
if domain.Role == nil {
|
||||||
log.Printf("No role found in meta data. Ignoring domain %q\n", d)
|
log.Printf("No role found in meta data for domain %q\n", d)
|
||||||
continue
|
// Assume trusted provider to continue report generation
|
||||||
|
role := csaf.MetadataRoleTrustedProvider
|
||||||
|
domain.Role = &role
|
||||||
}
|
}
|
||||||
|
|
||||||
rules := roleRequirements(*domain.Role)
|
rules := roleRequirements(*domain.Role)
|
||||||
|
|
@ -513,7 +516,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 = json.NewDecoder(bytes.NewReader(all)).Decode(&rolieDoc)
|
err = misc.StrictJSONParse(bytes.NewReader(all), &rolieDoc)
|
||||||
return rfeed, rolieDoc, err
|
return rfeed, rolieDoc, err
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -531,7 +534,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(strings.ReplaceAll(msg, `%`, `%%`))
|
p.badProviderMetadata.error("%s", strings.ReplaceAll(msg, `%`, `%%`))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -623,15 +626,9 @@ 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
|
||||||
|
|
@ -642,9 +639,8 @@ 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 := b.ResolveReference(fp).String()
|
u := fp.String()
|
||||||
|
|
||||||
// Should this URL be ignored?
|
// Should this URL be ignored?
|
||||||
if p.cfg.ignoreURL(u) {
|
if p.cfg.ignoreURL(u) {
|
||||||
|
|
@ -699,7 +695,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 json.NewDecoder(tee).Decode(&doc)
|
return misc.StrictJSONParse(tee, &doc)
|
||||||
}(); err != nil {
|
}(); err != nil {
|
||||||
lg(ErrorType, "Reading %s failed: %v", u, err)
|
lg(ErrorType, "Reading %s failed: %v", u, err)
|
||||||
continue
|
continue
|
||||||
|
|
@ -738,7 +734,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(fault)
|
p.badFolders.error("%s", 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:
|
||||||
|
|
@ -746,7 +742,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(fault)
|
p.badChanges.error("%s", fault)
|
||||||
} else {
|
} else {
|
||||||
p.timesAdv[f.URL()] = current
|
p.timesAdv[f.URL()] = current
|
||||||
}
|
}
|
||||||
|
|
@ -776,8 +772,7 @@ func (p *processor) integrity(
|
||||||
lg(ErrorType, "Bad URL %s: %v", x.url(), err)
|
lg(ErrorType, "Bad URL %s: %v", x.url(), err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
hu = makeAbs(hu)
|
hashFile := hu.String()
|
||||||
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 {
|
||||||
|
|
@ -817,7 +812,7 @@ func (p *processor) integrity(
|
||||||
msgType = InfoType
|
msgType = InfoType
|
||||||
}
|
}
|
||||||
for _, fetchError := range hashFetchErrors {
|
for _, fetchError := range hashFetchErrors {
|
||||||
p.badIntegrities.add(msgType, fetchError)
|
p.badIntegrities.add(msgType, "%s", fetchError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check signature
|
// Check signature
|
||||||
|
|
@ -826,8 +821,7 @@ func (p *processor) integrity(
|
||||||
lg(ErrorType, "Bad URL %s: %v", f.SignURL(), err)
|
lg(ErrorType, "Bad URL %s: %v", f.SignURL(), err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
su = makeAbs(su)
|
sigFile := su.String()
|
||||||
sigFile := b.ResolveReference(su).String()
|
|
||||||
p.checkTLS(sigFile)
|
p.checkTLS(sigFile)
|
||||||
|
|
||||||
p.badSignatures.use()
|
p.badSignatures.use()
|
||||||
|
|
@ -947,12 +941,13 @@ 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()
|
||||||
if _, err := url.Parse(u); err != nil {
|
up, err := url.Parse(u)
|
||||||
|
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: u})
|
files = append(files, csaf.DirectoryAdvisoryFile{Path: misc.JoinURL(bu, up).String()})
|
||||||
}
|
}
|
||||||
return files, scanner.Err()
|
return files, scanner.Err()
|
||||||
}()
|
}()
|
||||||
|
|
@ -967,7 +962,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, base, mask, p.badIndices.add)
|
return p.integrity(files, 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.
|
||||||
|
|
@ -1034,9 +1029,13 @@ func (p *processor) checkChanges(base string, mask whereType) error {
|
||||||
}
|
}
|
||||||
path := r[pathColumn]
|
path := r[pathColumn]
|
||||||
|
|
||||||
times, files =
|
pathURL, err := url.Parse(path)
|
||||||
append(times, t),
|
if err != nil {
|
||||||
append(files, csaf.DirectoryAdvisoryFile{Path: path})
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
@ -1051,7 +1050,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("no entries in changes.csv found" + filtered)
|
p.badChanges.warn("%s", "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 {
|
||||||
|
|
@ -1063,7 +1062,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, base, mask, p.badChanges.add)
|
return p.integrity(files, 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.
|
||||||
|
|
@ -1299,7 +1298,7 @@ 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: " +
|
"Unexpected situation while loading provider-metadata.json: %s",
|
||||||
lpmd.Messages[i].Message)
|
lpmd.Messages[i].Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1364,17 +1363,11 @@ func (p *processor) checkSecurityFolder(folder string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to load
|
// Try to load
|
||||||
up, err := url.Parse(u)
|
_, 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)
|
||||||
|
|
@ -1406,32 +1399,31 @@ 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,
|
||||||
fmt.Sprintf("Fetching %s failed: %v", path, err))
|
"Fetching %s failed: %v", path, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
p.badDNSPath.add(ErrorType, fmt.Sprintf("Fetching %s failed. Status code %d (%s)",
|
p.badDNSPath.add(ErrorType, "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,
|
||||||
fmt.Sprintf("Error while reading the response from %s", path))
|
"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,
|
||||||
fmt.Sprintf("%s does not serve the same provider-metadata.json as previously found",
|
"%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"
|
||||||
|
|
@ -1439,11 +1431,12 @@ 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,
|
||||||
fmt.Sprintf("Fetching %s failed: %v", path, err))
|
"Fetching %s failed: %v", path, err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
p.badWellknownMetadata.add(ErrorType, fmt.Sprintf("Fetching %s failed. Status code %d (%s)",
|
p.badWellknownMetadata.add(ErrorType, "Fetching %s failed. Status code %d (%s)",
|
||||||
path, res.StatusCode, res.Status))
|
path, res.StatusCode, res.Status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1480,13 +1473,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, sDMessage)
|
p.badSecurity.add(InfoType, "%s", sDMessage)
|
||||||
case 1:
|
case 1:
|
||||||
p.badSecurity.add(ErrorType, sDMessage)
|
p.badSecurity.add(ErrorType, "%s", sDMessage)
|
||||||
p.badSecurity.add(ErrorType, sLMessage)
|
p.badSecurity.add(ErrorType, "%s", sLMessage)
|
||||||
case 2:
|
case 2:
|
||||||
p.badSecurity.add(WarnType, sDMessage)
|
p.badSecurity.add(WarnType, "%s", sDMessage)
|
||||||
p.badSecurity.add(InfoType, sLMessage)
|
p.badSecurity.add(InfoType, "%s", sLMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.checkDNS(domain)
|
p.checkDNS(domain)
|
||||||
|
|
@ -1522,11 +1515,6 @@ 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 {
|
||||||
|
|
@ -1539,10 +1527,11 @@ func (p *processor) checkPGPKeys(_ string) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
u := base.ResolveReference(up).String()
|
// Todo: refactor all methods to directly accept *url.URL
|
||||||
|
u := up.String()
|
||||||
p.checkTLS(u)
|
p.checkTLS(u)
|
||||||
|
|
||||||
res, err := client.Get(u)
|
res, err := client.Get(*key.URL)
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -216,11 +216,6 @@ 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{}
|
||||||
|
|
@ -232,12 +227,11 @@ func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
|
||||||
if feed.URL == nil {
|
if feed.URL == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
up, err := url.Parse(string(*feed.URL))
|
feedBase, 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)
|
||||||
|
|
||||||
|
|
@ -264,13 +258,12 @@ func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
up, err := url.Parse(string(*feed.URL))
|
feedURL, 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)
|
||||||
|
|
@ -290,7 +283,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, feedBase, rolieMask, p.badProviderMetadata.add); err != nil {
|
if err := p.integrity(files, rolieMask, p.badProviderMetadata.add); err != nil {
|
||||||
if err != errContinue {
|
if err != errContinue {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -319,13 +312,12 @@ func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
up, err := url.Parse(string(*feed.URL))
|
feedBase, 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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -225,7 +226,7 @@ func (d *downloader) download(ctx context.Context, domain string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
base, err := url.Parse(lpmd.URL)
|
pmdURL, 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)
|
||||||
}
|
}
|
||||||
|
|
@ -235,7 +236,6 @@ 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,
|
||||||
base)
|
pmdURL)
|
||||||
|
|
||||||
// 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,7 +310,6 @@ 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)
|
||||||
|
|
@ -335,7 +334,7 @@ func (d *downloader) loadOpenPGPKeys(
|
||||||
if key.URL == nil {
|
if key.URL == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
up, err := url.Parse(*key.URL)
|
u, 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,
|
||||||
|
|
@ -343,9 +342,7 @@ func (d *downloader) loadOpenPGPKeys(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
u := base.ResolveReference(up).String()
|
res, err := client.Get(u.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",
|
||||||
|
|
@ -550,7 +547,7 @@ func (dc *downloadContext) downloadAdvisory(
|
||||||
|
|
||||||
tee := io.TeeReader(resp.Body, hasher)
|
tee := io.TeeReader(resp.Body, hasher)
|
||||||
|
|
||||||
if err := json.NewDecoder(tee).Decode(&doc); err != nil {
|
if err := misc.StrictJSONParse(tee, &doc); err != nil {
|
||||||
dc.stats.downloadFailed++
|
dc.stats.downloadFailed++
|
||||||
slog.Warn("Downloading failed",
|
slog.Warn("Downloading failed",
|
||||||
"url", file.URL(),
|
"url", file.URL(),
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -262,6 +263,14 @@ 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}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
@ -82,8 +81,9 @@ 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 {
|
||||||
log.Printf("Create failed: %s\n", resp.Status)
|
createError = fmt.Errorf("create failed: %s", 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 := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
if err := misc.StrictJSONParse(resp.Body, &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 nil
|
return createError
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 := json.NewDecoder(bytes.NewReader(data)).Decode(&doc); err != nil {
|
if err := misc.StrictJSONParse(bytes.NewReader(data), &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 := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
if err := misc.StrictJSONParse(resp.Body, &result); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -19,6 +18,7 @@ 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 = json.NewDecoder(f).Decode(&doc); err != nil {
|
if err = misc.StrictJSONParse(f, &doc); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return doc, err
|
return doc, err
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gocsaf/csaf/v3/internal/misc"
|
||||||
"github.com/gocsaf/csaf/v3/util"
|
"github.com/gocsaf/csaf/v3/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -95,7 +96,7 @@ type AdvisoryFileProcessor struct {
|
||||||
client util.Client
|
client util.Client
|
||||||
expr *util.PathEval
|
expr *util.PathEval
|
||||||
doc any
|
doc any
|
||||||
base *url.URL
|
pmdURL *url.URL
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAdvisoryFileProcessor constructs a filename extractor
|
// NewAdvisoryFileProcessor constructs a filename extractor
|
||||||
|
|
@ -104,13 +105,13 @@ func NewAdvisoryFileProcessor(
|
||||||
client util.Client,
|
client util.Client,
|
||||||
expr *util.PathEval,
|
expr *util.PathEval,
|
||||||
doc any,
|
doc any,
|
||||||
base *url.URL,
|
pmdURL *url.URL,
|
||||||
) *AdvisoryFileProcessor {
|
) *AdvisoryFileProcessor {
|
||||||
return &AdvisoryFileProcessor{
|
return &AdvisoryFileProcessor{
|
||||||
client: client,
|
client: client,
|
||||||
expr: expr,
|
expr: expr,
|
||||||
doc: doc,
|
doc: doc,
|
||||||
base: base,
|
pmdURL: pmdURL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,7 +180,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.base)
|
baseURL, err := util.BaseURL(afp.pmdURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -261,8 +262,13 @@ 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: base.JoinPath(path).String()})
|
DirectoryAdvisoryFile{Path: misc.JoinURL(base, pathURL).String()})
|
||||||
}
|
}
|
||||||
return files, nil
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
@ -276,12 +282,11 @@ func (afp *AdvisoryFileProcessor) processROLIE(
|
||||||
if feed.URL == nil {
|
if feed.URL == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
up, err := url.Parse(string(*feed.URL))
|
feedURL, 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)
|
||||||
|
|
@ -289,11 +294,6 @@ 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 feedBaseURL.ResolveReference(p).String()
|
return p.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
rfeed.Entries(func(entry *Entry) {
|
rfeed.Entries(func(entry *Entry) {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ 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.
|
||||||
|
|
@ -383,7 +385,6 @@ 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.
|
||||||
|
|
@ -446,6 +447,7 @@ 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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -609,8 +611,10 @@ type Remediation struct {
|
||||||
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"`
|
||||||
|
//revive:enable
|
||||||
RestartRequired *RestartRequired `json:"restart_required,omitempty"`
|
RestartRequired *RestartRequired `json:"restart_required,omitempty"`
|
||||||
URL *string `json:"url,omitempty"`
|
URL *string `json:"url,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
@ -741,8 +745,10 @@ 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.
|
||||||
|
|
@ -885,8 +891,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.Version == nil {
|
if e.Name == nil {
|
||||||
return errors.New("'version' is missing")
|
return errors.New("'name' is missing")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -1391,7 +1397,7 @@ func LoadAdvisory(fname string) (*Advisory, error) {
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
var advisory Advisory
|
var advisory Advisory
|
||||||
if err := json.NewDecoder(f).Decode(&advisory); err != nil {
|
if err := misc.StrictJSONParse(f, &advisory); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := advisory.Validate(); err != nil {
|
if err := advisory.Validate(); err != nil {
|
||||||
|
|
|
||||||
46
csaf/advisory_test.go
Normal file
46
csaf/advisory_test.go
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,11 @@
|
||||||
// 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
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/format"
|
"go/format"
|
||||||
|
|
@ -22,6 +21,8 @@ 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
|
||||||
|
|
@ -98,7 +99,7 @@ func loadSchema(filename string) (*schema, error) {
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
var s schema
|
var s schema
|
||||||
if err := json.NewDecoder(f).Decode(&s); err != nil {
|
if err := misc.StrictJSONParse(f, &s); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &s, nil
|
return &s, nil
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gocsaf/csaf/v3/internal/misc"
|
||||||
"github.com/gocsaf/csaf/v3/util"
|
"github.com/gocsaf/csaf/v3/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -575,7 +576,6 @@ 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,8 +695,7 @@ 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
|
||||||
dec := json.NewDecoder(r)
|
if err := misc.StrictJSONParse(r, &pmd); err != nil {
|
||||||
if err := dec.Decode(&pmd); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,7 +149,6 @@ 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.
|
||||||
|
|
@ -323,7 +322,7 @@ func (pmdl *ProviderMetadataLoader) loadFromURL(path string) *LoadedProviderMeta
|
||||||
|
|
||||||
var doc any
|
var doc any
|
||||||
|
|
||||||
if err := json.NewDecoder(tee).Decode(&doc); err != nil {
|
if err := misc.StrictJSONParse(tee, &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))
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/gocsaf/csaf/v3/internal/misc"
|
||||||
bolt "go.etcd.io/bbolt"
|
bolt "go.etcd.io/bbolt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -180,7 +181,6 @@ 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 := json.NewDecoder(r).Decode(&rvr); err != nil {
|
if err := misc.StrictJSONParse(r, &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 json.NewDecoder(in).Decode(&rvr)
|
return misc.StrictJSONParse(in, &rvr)
|
||||||
}(); err != nil {
|
}(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gocsaf/csaf/v3/internal/misc"
|
||||||
"github.com/gocsaf/csaf/v3/util"
|
"github.com/gocsaf/csaf/v3/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -54,7 +55,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 := json.NewDecoder(r).Decode(&rsd); err != nil {
|
if err := misc.StrictJSONParse(r, &rsd); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &rsd, nil
|
return &rsd, nil
|
||||||
|
|
@ -122,7 +123,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 := json.NewDecoder(r).Decode(&rcd); err != nil {
|
if err := misc.StrictJSONParse(r, &rcd); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &rcd, nil
|
return &rcd, nil
|
||||||
|
|
@ -168,14 +169,22 @@ type Format struct {
|
||||||
|
|
||||||
// Entry for ROLIE.
|
// Entry for ROLIE.
|
||||||
type Entry struct {
|
type Entry struct {
|
||||||
|
Base *string `json:"base,omitempty"`
|
||||||
|
LanguageTag *string `json:"lang,omitempty"`
|
||||||
|
Author *json.RawMessage `json:"author,omitempty"`
|
||||||
|
Category []ROLIECategory `json:"category,omitempty"`
|
||||||
|
Content Content `json:"content"`
|
||||||
|
Contributor *json.RawMessage `json:"contributor,omitempty"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Titel string `json:"title"`
|
|
||||||
Link []Link `json:"link"`
|
Link []Link `json:"link"`
|
||||||
Published TimeStamp `json:"published"`
|
Published TimeStamp `json:"published"`
|
||||||
Updated TimeStamp `json:"updated"`
|
Rights *json.RawMessage `json:"rights,omitempty"`
|
||||||
|
Source *json.RawMessage `json:"source,omitempty"`
|
||||||
Summary *Summary `json:"summary,omitempty"`
|
Summary *Summary `json:"summary,omitempty"`
|
||||||
Content Content `json:"content"`
|
Titel string `json:"title"`
|
||||||
|
Updated TimeStamp `json:"updated"`
|
||||||
Format Format `json:"format"`
|
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.
|
||||||
|
|
@ -195,9 +204,8 @@ 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 := dec.Decode(&rf); err != nil {
|
if err := misc.StrictJSONParse(r, &rf); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &rf, nil
|
return &rf, nil
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,17 @@ package csaf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
_ "embed" // Used for embedding.
|
_ "embed" // Used for embedding.
|
||||||
"io"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/santhosh-tekuri/jsonschema/v5"
|
"github.com/santhosh-tekuri/jsonschema/v6"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed schema/csaf_json_schema.json
|
//go:embed schema/csaf_json_schema.json
|
||||||
|
|
@ -64,13 +68,28 @@ var (
|
||||||
compiledRolieSchema = compiledSchema{url: rolieSchemaURL}
|
compiledRolieSchema = compiledSchema{url: rolieSchemaURL}
|
||||||
)
|
)
|
||||||
|
|
||||||
// loadURL loads the content of an URL from embedded data or
|
type schemaLoader http.Client
|
||||||
// falls back to the global loader function of the jsonschema package.
|
|
||||||
func loadURL(s string) (io.ReadCloser, error) {
|
func (l *schemaLoader) loadHTTPURL(url string) (any, error) {
|
||||||
loader := func(data []byte) (io.ReadCloser, error) {
|
client := (*http.Client)(l)
|
||||||
return io.NopCloser(bytes.NewReader(data)), nil
|
resp, err := client.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
switch s {
|
defer resp.Body.Close()
|
||||||
|
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:
|
||||||
|
|
@ -86,14 +105,27 @@ func loadURL(s string) (io.ReadCloser, error) {
|
||||||
case rolieSchemaURL:
|
case rolieSchemaURL:
|
||||||
return loader(rolieSchema)
|
return loader(rolieSchema)
|
||||||
default:
|
default:
|
||||||
return jsonschema.LoadURL(s)
|
// Fallback to http loader
|
||||||
|
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 = true
|
c.AssertFormat()
|
||||||
c.LoadURL = loadURL
|
c.UseLoader(newSchemaLoader(false))
|
||||||
cs.compiled, cs.err = c.Compile(cs.url)
|
cs.compiled, cs.err = c.Compile(cs.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,7 +141,8 @@ func (cs *compiledSchema) validate(doc any) ([]string, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
valErr, ok := err.(*jsonschema.ValidationError)
|
var valErr *jsonschema.ValidationError
|
||||||
|
ok := errors.As(err, &valErr)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -133,21 +166,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 < errs[j].Error
|
return errs[i].Error.String() < errs[j].Error.String()
|
||||||
})
|
})
|
||||||
|
|
||||||
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 == "" {
|
if e.Error == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
loc := e.InstanceLocation
|
loc := e.InstanceLocation
|
||||||
if loc == "" {
|
if loc == "" {
|
||||||
loc = e.AbsoluteKeywordLocation
|
loc = e.AbsoluteKeywordLocation
|
||||||
}
|
}
|
||||||
res = append(res, loc+": "+e.Error)
|
res = append(res, loc+": "+e.Error.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
|
|
|
||||||
|
|
@ -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.23 and 1.24).
|
the latest version of Go (currently 1.24 and 1.25).
|
||||||
|
|
||||||
## Generated files
|
## Generated files
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -247,3 +247,9 @@ 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.)
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,13 @@ 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.
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,12 @@ 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:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
@ -69,7 +75,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
|
||||||
ignoresigcheck = false
|
ignore_sigcheck = 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
|
||||||
|
|
@ -104,8 +110,9 @@ ignorepattern = [".*white.*", ".*red.*"]
|
||||||
|
|
||||||
#### Timerange option
|
#### Timerange option
|
||||||
|
|
||||||
The `timerange` parameter enables downloading advisories which last changes falls
|
The `time_range` parameter enables downloading advisories
|
||||||
into a given intervall. There are three possible notations:
|
which last changes falls into a given intervall.
|
||||||
|
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),
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,8 @@ 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 a password and a valid Client Certificate for write access.
|
# Require users to use both
|
||||||
|
# (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
|
||||||
|
|
|
||||||
|
|
@ -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/create --cert-type p12 --cert {clientCertificat.p12}
|
curl https://192.168.56.102/cgi-bin/csaf_provider.go/api/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.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
Scripts for assisting the Integration tests.
|
Scripts for assisting the Integration tests.
|
||||||
They were written on Ubuntu 20.04 TLS amd64 and also tested with 24.04 TLS.
|
They were written on Ubuntu 20.04 LTS amd64 and also tested with 24.04 LTS.
|
||||||
|
|
||||||
- `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
34
go.mod
|
|
@ -1,31 +1,33 @@
|
||||||
module github.com/gocsaf/csaf/v3
|
module github.com/gocsaf/csaf/v3
|
||||||
|
|
||||||
go 1.22.9
|
go 1.24.9
|
||||||
|
|
||||||
|
toolchain go1.25.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.4.0
|
github.com/BurntSushi/toml v1.5.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.8.0
|
github.com/ProtonMail/gopenpgp/v2 v2.9.0
|
||||||
github.com/PuerkitoBio/goquery v1.8.1
|
github.com/PuerkitoBio/goquery v1.11.0
|
||||||
github.com/gofrs/flock v0.12.1
|
github.com/gofrs/flock v0.13.0
|
||||||
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/v5 v5.3.1
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
|
||||||
go.etcd.io/bbolt v1.3.11
|
go.etcd.io/bbolt v1.4.3
|
||||||
golang.org/x/crypto v0.29.0
|
golang.org/x/crypto v0.46.0
|
||||||
golang.org/x/term v0.26.0
|
golang.org/x/term v0.38.0
|
||||||
golang.org/x/time v0.8.0
|
golang.org/x/time v0.14.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/ProtonMail/go-crypto v1.1.2 // indirect
|
github.com/ProtonMail/go-crypto v1.3.0 // 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.2 // indirect
|
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||||
github.com/cloudflare/circl v1.5.0 // indirect
|
github.com/cloudflare/circl v1.6.1 // 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.31.0 // indirect
|
golang.org/x/net v0.48.0 // indirect
|
||||||
golang.org/x/sys v0.27.0 // indirect
|
golang.org/x/sys v0.39.0 // indirect
|
||||||
golang.org/x/text v0.20.0 // indirect
|
golang.org/x/text v0.32.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
114
go.sum
114
go.sum
|
|
@ -1,28 +1,30 @@
|
||||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.5.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.1.2 h1:A7JbD57ThNqh7XjmHE+PXpQ3Dqt3BrSAC0AL0Go3KS0=
|
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
|
||||||
github.com/ProtonMail/go-crypto v1.1.2/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
|
||||||
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.8.0 h1:WvMv3CMcFsqKSM4/Qf8sf3tgyQkzDqQmoSE49bnBuP4=
|
github.com/ProtonMail/gopenpgp/v2 v2.9.0 h1:ruLzBmwe4dR1hdnrsEJ/S7psSBmV15gFttFUPP/+/kE=
|
||||||
github.com/ProtonMail/gopenpgp/v2 v2.8.0/go.mod h1:qb2GUSnmA9ipBW5GVtCtEhkummSlqs2A8Ar3S0HBgSY=
|
github.com/ProtonMail/gopenpgp/v2 v2.9.0/go.mod h1:IldDyh9Hv1ZCCYatTuuEt1XZJ0OPjxLpTarDfglih7s=
|
||||||
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
|
github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw=
|
||||||
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
|
github.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ=
|
||||||
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
|
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
|
||||||
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
|
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
|
||||||
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
|
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||||
github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
|
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||||
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/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
|
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
|
||||||
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
|
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw=
|
||||||
|
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=
|
||||||
|
|
@ -31,67 +33,93 @@ 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/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
|
||||||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
|
||||||
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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
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.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
|
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
|
||||||
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
|
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
|
||||||
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.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
|
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.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.6.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.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.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.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
|
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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
|
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=
|
||||||
|
|
|
||||||
|
|
@ -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/privated.pem"
|
privateKey = "data/private.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.")
|
t.Errorf("Failure: Couldn't load supposedly valid certificate. Got error: %v", err)
|
||||||
}
|
}
|
||||||
// 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.")
|
t.Errorf("Failure: Couldn't load supposedly valid encrypted certificate. Got error: %v", err)
|
||||||
}
|
}
|
||||||
// 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 error.
|
// Try to load nonexistent encrypted cert, expecting success.
|
||||||
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.")
|
t.Errorf("Failure: Expected nil return. Got error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
60
internal/certs/createTestCerts.sh
Executable file
60
internal/certs/createTestCerts.sh
Executable file
|
|
@ -0,0 +1,60 @@
|
||||||
|
#!/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
|
||||||
|
|
@ -1,37 +1,28 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
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
|
||||||
WYXKZqig5qDyfzBvlXWEio/5GrDwgQIDAQABo4IBWzCCAVcwgcIGA1UdEQSBujCB
|
2xHzce3mi4RlANT4nOSdpELhl54xeJDgI9Evt70N8B4uTmOI5+F6JVICE25cnDs1
|
||||||
t4IrYSBkbnNOYW1lIG9mIHRoZSBzdWJqZWN0IG9mIHRoZSBjZXJ0aWZpY2F0ZYI3
|
c9SoHpWzh1ZuzfiBYa/cdQNUtaTfgHLi5GYtV1DzmKXVRUciBiNBWWxYMbTGvTOO
|
||||||
YW4gYWRkaXRpb25hbCBkbnNOYW1lIG9mIHRoZSBzdWJqZWN0IG9mIHRoZSBjZXJ0
|
i3r6DEgOYuukeL4qj//EGOcTJEarHVSxPMuXTD/PoP/VpIdqRS9drEpFUC6lecZc
|
||||||
aWZpY2F0ZYIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIP
|
UJtUPAcyx0oD2vNmPmulDfYFMLLOPrIeNa0g7os4wgUl7+9wR1cPPRTXY0fW6Hoi
|
||||||
c2Vjb25kIGFkZGl0aW9ugg50aGlyZCBhZGRpdGlvboIHZG5zTmFtZTAMBgNVHRMB
|
j+a8Qn80Q3PrOuEO/SZ4aHHpOk90bRqofyIhFjPwS0YN5w/Sn23uq1u2Dx+Zy+5K
|
||||||
Af8EAjAAMDEGA1UdJQQqMCgGCCsGAQUFBwMJBggrBgEFBQcDAgYIKwYBBQUHAwEG
|
6Cs9p5dJWu5/zU4ZdbQlpYIHXQVbido1TY92Z84skEsac2wVh7L2LMB3p3Gu9WYn
|
||||||
CCsGAQUFBwMCMA8GA1UdDwEB/wQFAwMHsAAwHQYDVR0OBBYEFKrFhODjTKCopb+W
|
oKqFYCw5FICvRgyh1KG8QWhW59Em0Jxr8rTw6qyBQACdixKy6/1ok2ArMivTC8Gd
|
||||||
Qa29PsHR4HXgMB8GA1UdIwQYMBaAFCyZxCa1ZUHVy8LjikE8zumAiEgfMA0GCSqG
|
rEbefshgc6dnAZCAp1MjCU+tg9iYEymSSLdOtUKvHEIosUGO1p5ol0hReTQ=
|
||||||
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-----
|
||||||
|
|
|
||||||
42
internal/certs/data/private.pem
Normal file
42
internal/certs/data/private.pem
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
Proc-Type: 4,ENCRYPTED
|
||||||
|
DEK-Info: AES-256-CBC,3ACC7169D177F0159193ACAF3B3997A3
|
||||||
|
|
||||||
|
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
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
Proc-Type: 4,ENCRYPTED
|
|
||||||
DEK-Info: DES-CBC,054A583F6C90570F
|
|
||||||
|
|
||||||
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
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
||||||
|
|
@ -1,27 +1,26 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIEkDCCAvigAwIBAgIBFDANBgkqhkiG9w0BAQsFADBKMQ8wDQYDVQQDEwZUZXN0
|
MIIEeDCCAuCgAwIBAgIUTqTcNqmr8Ou/MpL1AUnM/3gcoUkwDQYJKoZIhvcNAQEL
|
||||||
ZXIxKjAoBgNVBAoTIUNTQUYgVG9vbHMgRGV2ZWxvcG1lbnQgKGludGVybmFsKTEL
|
BQAwSjELMAkGA1UEBhMCREUxKjAoBgNVBAoTIUNTQUYgVG9vbHMgRGV2ZWxvcG1l
|
||||||
MAkGA1UEBhMCREUwHhcNMjMwOTA0MDcyMjAzWhcNMjMxMDI0MDcyMjAzWjBVMRow
|
bnQgKGludGVybmFsKTEPMA0GA1UEAxMGVGVzdGVyMCAXDTI1MTAxNzEwMjIzNloY
|
||||||
GAYDVQQDExFUTFMgVGVzdCBDbGllbnQgMTEqMCgGA1UEChMhQ1NBRiBUb29scyBE
|
DzIxMjUwOTIzMTAyMjM2WjBKMQswCQYDVQQGEwJERTEqMCgGA1UEChMhQ1NBRiBU
|
||||||
ZXZlbG9wbWVudCAoaW50ZXJuYWwpMQswCQYDVQQGEwJERTCCAaIwDQYJKoZIhvcN
|
b29scyBEZXZlbG9wbWVudCAoaW50ZXJuYWwpMQ8wDQYDVQQDEwZUZXN0ZXIwggGi
|
||||||
AQEBBQADggGPADCCAYoCggGBAN0vZbLXtRzd61rR8Hos0BGnqCaJXIwGARwxJojM
|
MA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDBN4fIBbwuGJXjXoa6F7e4Zzin
|
||||||
yxASFT+KeC4QDRkgRrK6OY4k/i7TEHuUGk/Bm754++554wmmhDqv1Q4+VhhR1K/J
|
Yd9EB4nt5TkNoMkRgQe0JIJ+t1/lS/xlI7ATxNjUdybnYwCrEfDvy8XGwN6te+Xh
|
||||||
Az/HVZNTAR1rPKwG82lyEpPxlRNZg/QtF9DqQSoSkL/fJLs+rq4zlKozXzREauZ5
|
dz6HKDWPijW+ritQW9kouxJJSpna95L8SqU4tjdfyL/2X9E/7j3VYw1//zcmhLJg
|
||||||
Be8So1dXRZfMVUMDgtk+IX8+iCeZisiWfv62ttQ0EiuiXLagd6ruEuoCSVi2tVsw
|
1Os0+JHPcPuj1vmwLa1v7eGTCNlt0K8DbrlhPlteJB3hWolNIoVDjRemZFmqwUeV
|
||||||
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
|
||||||
enRZb3oiVYFVDh0Hymz9g5VraMw=
|
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|
|
||||||
|
|
@ -3,180 +3,180 @@ Public Key Info:
|
||||||
Key Security Level: High (3072 bits)
|
Key Security Level: High (3072 bits)
|
||||||
|
|
||||||
modulus:
|
modulus:
|
||||||
00:dd:2f:65:b2:d7:b5:1c:dd:eb:5a:d1:f0:7a:2c:d0
|
00:c1:37:87:c8:05:bc:2e:18:95:e3:5e:86:ba:17:b7
|
||||||
11:a7:a8:26:89:5c:8c:06:01:1c:31:26:88:cc:cb:10
|
b8:67:38:a7:61:df:44:07:89:ed:e5:39:0d:a0:c9:11
|
||||||
12:15:3f:8a:78:2e:10:0d:19:20:46:b2:ba:39:8e:24
|
81:07:b4:24:82:7e:b7:5f:e5:4b:fc:65:23:b0:13:c4
|
||||||
fe:2e:d3:10:7b:94:1a:4f:c1:9b:be:78:fb:ee:79:e3
|
d8:d4:77:26:e7:63:00:ab:11:f0:ef:cb:c5:c6:c0:de
|
||||||
09:a6:84:3a:af:d5:0e:3e:56:18:51:d4:af:c9:03:3f
|
ad:7b:e5:e1:77:3e:87:28:35:8f:8a:35:be:ae:2b:50
|
||||||
c7:55:93:53:01:1d:6b:3c:ac:06:f3:69:72:12:93:f1
|
5b:d9:28:bb:12:49:4a:99:da:f7:92:fc:4a:a5:38:b6
|
||||||
95:13:59:83:f4:2d:17:d0:ea:41:2a:12:90:bf:df:24
|
37:5f:c8:bf:f6:5f:d1:3f:ee:3d:d5:63:0d:7f:ff:37
|
||||||
bb:3e:ae:ae:33:94:aa:33:5f:34:44:6a:e6:79:05:ef
|
26:84:b2:60:d4:eb:34:f8:91:cf:70:fb:a3:d6:f9:b0
|
||||||
12:a3:57:57:45:97:cc:55:43:03:82:d9:3e:21:7f:3e
|
2d:ad:6f:ed:e1:93:08:d9:6d:d0:af:03:6e:b9:61:3e
|
||||||
88:27:99:8a:c8:96:7e:fe:b6:b6:d4:34:12:2b:a2:5c
|
5b:5e:24:1d:e1:5a:89:4d:22:85:43:8d:17:a6:64:59
|
||||||
b6:a0:77:aa:ee:12:ea:02:49:58:b6:b5:5b:30:b0:2f
|
aa:c1:47:95:19:9f:d7:26:8b:3b:39:30:74:ee:9d:3c
|
||||||
c7:a7:c0:08:d9:1a:39:ea:69:87:89:6b:61:b9:a7:b5
|
c8:23:85:84:b9:7d:8d:70:a0:10:30:e4:2a:67:27:02
|
||||||
1f:cc:83:59:41:4b:49:ef:40:41:6e:b9:a8:2f:f1:55
|
29:77:62:18:ee:76:51:06:4a:37:73:14:bb:24:54:3e
|
||||||
48:28:fe:73:29:2b:60:58:54:52:9b:ef:44:cc:8e:5f
|
31:ae:d4:39:1a:c6:dd:24:7c:87:85:c5:1d:82:1f:af
|
||||||
dd:64:cd:10:9f:5b:5d:88:dc:aa:0a:46:c8:85:78:e4
|
a9:7d:9b:15:29:25:c1:dc:15:8a:5d:6a:21:41:07:9f
|
||||||
95:9b:d9:62:13:be:d7:94:cf:92:00:d7:0e:ca:91:52
|
1a:5c:44:c6:a5:b9:94:38:bb:5b:42:80:d8:4a:35:01
|
||||||
3a:53:ac:b6:57:2c:6a:c3:e9:72:31:09:12:d9:19:8e
|
eb:27:35:50:9f:56:91:54:06:1d:5f:53:f1:7e:82:1b
|
||||||
98:ad:47:ec:15:38:d4:0b:a2:6b:52:b0:11:f3:36:3b
|
e7:0b:74:fb:6e:4c:89:5c:3c:cb:c1:1c:ac:c1:fd:ed
|
||||||
48:bb:18:37:9b:14:98:55:12:32:92:67:23:e4:ff:48
|
2b:36:e9:e3:40:b4:b7:87:64:da:d8:f5:a9:6a:c7:f0
|
||||||
3e:29:ff:40:97:ac:aa:db:30:e8:d6:42:ac:fa:15:7f
|
ac:f2:03:a2:23:cc:00:d8:d8:1a:d7:7f:2d:66:e0:89
|
||||||
d6:1c:fc:6f:b3:01:8a:1e:4e:73:1d:81:87:af:3c:7b
|
45:7b:03:3a:7a:26:f5:1a:ed:74:f2:da:8e:14:9b:ee
|
||||||
38:a9:9f:55:ae:a0:cd:48:19:49:f3:87:8f:6c:4e:39
|
7d:f7:22:af:19:0e:16:15:18:42:26:da:97:39:30:9c
|
||||||
1d:94:9f:d0:f0:35:ab:c8:ae:64:82:59:85:ca:66:a8
|
5a:23:9d:d5:7b:65:a1:99:e9:85:3d:f6:30:50:0b:73
|
||||||
a0:e6:a0:f2:7f:30:6f:95:75:84:8a:8f:f9:1a:b0:f0
|
74:68:30:ac:1a:18:f4:c7:9c:85:db:4d:2c:66:6a:1f
|
||||||
81:
|
11:
|
||||||
|
|
||||||
public exponent:
|
public exponent:
|
||||||
01:00:01:
|
01:00:01:
|
||||||
|
|
||||||
private exponent:
|
private exponent:
|
||||||
14:ff:c0:f9:ff:bc:b4:26:e5:87:53:d3:2e:e6:3e:42
|
70:0e:fd:af:d3:2b:ad:6c:52:d9:f8:43:99:00:12:6c
|
||||||
ce:d6:0a:02:94:84:be:b5:30:46:02:50:8e:90:e0:cf
|
5f:69:2b:22:87:33:54:4f:f9:69:fc:e9:db:7b:61:ac
|
||||||
b6:b0:b7:a6:bd:48:cc:d5:8b:d8:ea:72:ff:af:dd:17
|
7c:c4:4c:7c:66:73:81:a9:61:a5:73:1e:fc:8a:aa:9a
|
||||||
3c:be:d1:1b:ca:6d:cd:10:a6:86:a8:d9:d2:44:44:27
|
ba:b6:94:18:94:81:99:b5:a1:0f:e2:15:c5:4c:ac:98
|
||||||
d0:65:51:65:0c:27:34:07:dc:7b:38:64:10:03:7c:f4
|
df:07:96:f8:ea:89:c6:97:31:b5:8d:b0:16:21:46:cc
|
||||||
a1:cd:40:de:24:3a:e0:21:bc:ef:33:1d:9f:61:e8:57
|
ce:28:62:3e:9b:c5:29:70:26:2f:d8:24:8e:a8:52:7d
|
||||||
ac:e4:9c:c0:7b:df:7c:f8:20:83:ac:0b:8e:0b:d3:62
|
d1:0e:83:ce:a7:09:9b:d3:57:87:3f:98:5f:c8:ab:ba
|
||||||
eb:8a:8e:03:5b:a3:e5:08:ae:df:a7:fe:85:92:e8:a5
|
aa:31:2e:19:ae:84:1d:39:ab:9e:b2:42:f6:75:ff:68
|
||||||
ae:58:46:72:d6:fc:91:43:b1:7b:a4:c0:5f:51:c3:50
|
ae:73:00:fa:d7:a4:c5:3d:7c:4f:54:65:4e:1c:88:e6
|
||||||
0d:e2:67:e8:af:51:13:41:a9:8d:ef:fb:a1:a4:e2:84
|
c2:b5:9d:a2:ca:38:61:45:09:17:01:68:5a:f7:4e:4d
|
||||||
7c:2b:a0:50:c5:fe:ed:84:a5:25:83:86:4a:d3:0f:56
|
cb:24:f1:e3:57:a1:97:58:1e:b3:ef:57:91:e0:1d:95
|
||||||
37:38:e6:1e:26:7d:45:22:0b:ba:22:35:be:f8:8b:1b
|
51:8c:a9:4a:4e:f7:cd:fe:f7:04:f3:ff:67:ad:e7:01
|
||||||
72:90:13:c4:1f:c5:d1:34:b5:0e:b2:ee:f7:e1:b9:5e
|
14:dc:7e:e4:00:c0:38:51:2f:04:db:39:6c:f1:1b:a4
|
||||||
a2:29:8d:f9:6e:23:4b:50:8f:35:c8:a9:f3:d2:1f:dd
|
a5:f1:b4:5a:c3:17:d2:41:1a:5a:b5:f3:69:3b:b8:ba
|
||||||
ce:a0:96:50:2d:2e:af:cf:b5:e1:20:e7:e9:d2:49:ed
|
7b:59:96:d7:b2:c2:2c:9a:dd:e9:42:ce:fb:c8:22:fc
|
||||||
b5:0e:5b:3e:d1:4b:f1:fa:c2:73:3a:1b:51:34:7e:75
|
c5:33:97:6d:68:89:cd:e5:bc:2e:cc:9d:23:65:18:04
|
||||||
30:06:d2:47:d2:a8:2a:45:be:16:fb:8f:63:84:85:b7
|
0c:83:b6:35:7e:16:09:96:d1:48:61:31:b1:ce:f8:50
|
||||||
bf:f7:c4:c5:3d:95:56:8c:d1:02:7f:58:ac:4d:11:7b
|
f0:14:ba:57:2f:02:1b:61:9c:bc:81:c1:ef:b3:bf:2f
|
||||||
c5:55:f3:c8:4e:d7:d9:aa:62:b0:e3:1e:04:5c:97:d1
|
fb:36:af:18:8c:90:40:55:5a:fd:a7:d4:ed:3b:94:a6
|
||||||
ca:e2:71:aa:8b:33:b4:34:e9:04:d4:70:7c:f4:cb:57
|
df:ab:eb:6c:d2:bc:e3:80:7e:d5:06:21:28:9b:04:65
|
||||||
19:c1:03:23:f4:bc:4d:91:8f:b2:9a:99:1c:6c:81:2d
|
b5:cc:04:b2:44:e9:2d:3b:7d:de:24:90:8d:fb:90:2d
|
||||||
4d:2d:e9:a1:e3:ce:e3:c9:62:52:89:1f:47:86:61:f1
|
40:17:51:cf:a7:fa:ee:54:89:8f:c0:f4:e4:c2:bd:44
|
||||||
dd:bc:46:8d:79:0a:99:9d:aa:4b:a9:0a:72:54:db:dc
|
94:1d:8d:fc:b7:d7:05:4d:46:dc:63:1f:7f:d8:b4:8b
|
||||||
ae:48:be:60:4a:73:99:d8:3c:9e:07:78:05:df:87:39
|
11:db:37:be:4d:e9:2b:33:b9:6b:8c:a7:f0:43:56:c5
|
||||||
|
|
||||||
|
|
||||||
prime1:
|
prime1:
|
||||||
00:e9:63:0f:d7:49:31:27:a8:36:fe:95:bd:8d:05:c1
|
00:f0:57:25:fd:aa:7e:98:13:08:28:99:16:eb:af:2e
|
||||||
35:48:2e:03:4f:a6:57:54:3a:a4:95:3f:8e:9f:28:7c
|
22:f6:e6:d7:bd:df:49:57:17:71:bf:21:ba:bf:75:54
|
||||||
d2:df:af:54:36:9e:7c:9f:c3:b9:64:8f:c0:b0:96:3c
|
5a:38:92:64:8c:4a:10:d4:4f:77:18:44:c2:79:f0:9d
|
||||||
aa:01:f6:9a:be:83:e2:85:20:0d:33:de:88:97:af:6f
|
72:26:2e:9a:27:5d:e7:41:0b:c6:65:cb:fa:89:6d:9b
|
||||||
be:3f:53:5a:a3:77:02:fd:81:17:91:3b:b2:2d:ab:78
|
fb:87:78:e2:87:22:d4:92:21:f5:3a:57:fa:b0:bf:bb
|
||||||
db:d9:43:db:04:69:82:61:30:e4:96:ac:88:8b:f6:3f
|
66:a2:bf:43:af:e8:58:b4:e2:a1:ed:97:62:09:0d:49
|
||||||
56:c4:49:fd:d5:e5:8c:9d:30:ad:cf:d9:8d:5c:87:b5
|
ca:4c:99:a2:f4:f3:31:df:80:8e:56:be:64:9d:72:59
|
||||||
27:4b:09:8e:19:ed:e2:11:3f:69:b2:47:be:70:39:11
|
ef:e9:db:4d:a3:e2:cf:79:1e:99:89:b2:f1:e3:2d:bc
|
||||||
41:a3:db:bb:b9:0e:e4:7b:50:d0:d2:c2:89:81:36:b9
|
8f:a0:2a:2f:a6:f0:21:18:2d:f1:57:20:55:c1:c9:18
|
||||||
6b:a6:fe:94:5b:06:66:e6:ed:86:52:42:5e:a9:0e:18
|
c1:64:c6:9c:00:df:b2:54:55:8d:fe:d3:46:a0:5c:2e
|
||||||
db:18:f9:14:21:3d:e0:3c:8d:79:c3:f5:d2:cc:51:65
|
f8:f7:10:b6:27:3a:4a:79:a1:14:b1:0c:c3:72:5b:2b
|
||||||
fb:1c:49:ed:0a:d5:33:99:34:16:f9:1d:68:4a:78:da
|
66:d6:85:2c:7e:58:72:eb:33:62:73:34:e5:38:87:2e
|
||||||
5f:
|
17:
|
||||||
|
|
||||||
prime2:
|
prime2:
|
||||||
00:f2:9d:ae:5f:bd:b7:a3:87:a7:8d:30:46:06:8b:15
|
00:cd:ce:5d:fb:04:16:34:f4:de:02:7d:00:07:3e:b0
|
||||||
a9:e5:a9:58:1c:2b:3a:7e:78:35:36:56:31:42:df:46
|
94:8c:f4:3a:62:05:37:1a:4f:d8:40:2e:31:11:07:77
|
||||||
87:e8:57:0d:6e:99:de:cf:fb:a8:72:16:71:4b:b3:ad
|
09:8b:bd:76:6e:85:b9:43:df:3f:86:cb:db:6d:fe:c6
|
||||||
ed:74:07:cb:cf:7d:2b:12:89:66:c4:0f:8a:ea:e3:37
|
4c:ca:e1:16:ce:5c:0e:e1:b1:10:0d:8d:48:99:d7:43
|
||||||
17:2c:75:92:11:7a:a6:da:29:24:33:9b:69:c2:64:68
|
7f:6c:b6:20:b2:cd:0c:56:26:02:18:81:e1:67:e5:cd
|
||||||
03:db:31:de:fe:1d:a2:4d:9d:91:9f:f0:50:b8:8f:d0
|
b3:66:1e:77:dc:49:6a:5d:8c:9c:0e:24:14:3e:a1:4a
|
||||||
22:11:b9:b0:95:98:5e:65:bf:45:97:9b:35:f2:98:27
|
7e:cf:72:e6:e4:03:e6:38:41:fa:2b:91:71:6c:33:b0
|
||||||
46:7c:b2:86:eb:7b:8b:57:f2:c3:49:47:7d:01:4a:9a
|
ec:07:3a:be:5b:f8:74:f5:e4:1f:9c:c4:d0:d4:75:a8
|
||||||
b0:e6:67:05:e5:61:7a:ab:63:c8:cb:d8:44:69:88:72
|
35:09:05:0f:7f:54:4e:2a:bc:cc:92:de:1e:f4:74:8a
|
||||||
a5:a9:60:89:60:df:e6:d9:4d:16:2b:35:7b:20:00:f3
|
56:36:e0:b1:37:cf:b3:9c:57:05:76:59:69:c3:03:de
|
||||||
3c:d1:78:f9:22:eb:48:c3:7f:78:63:e6:34:60:48:30
|
c2:33:0c:c4:a1:4f:2a:b8:3c:20:63:c9:58:96:1a:e2
|
||||||
66:02:bb:38:c2:94:2e:b9:86:b2:2f:9a:4f:17:7f:e1
|
62:ce:bf:fb:a9:51:b0:66:99:35:d6:d2:60:59:72:bd
|
||||||
1f:
|
17:
|
||||||
|
|
||||||
coefficient:
|
coefficient:
|
||||||
00:93:3e:7c:b9:ea:87:52:37:fa:d5:0a:36:fb:e1:d0
|
33:6a:05:3e:1e:46:46:58:e2:61:38:6a:c2:8f:77:a2
|
||||||
fc:62:4d:00:0b:ad:a8:fb:bd:34:53:96:c2:6c:a1:6a
|
27:b7:19:38:75:40:d6:8c:87:bc:65:a6:24:c3:97:e5
|
||||||
49:b7:a0:24:33:16:95:79:14:ac:bb:75:8d:78:e9:10
|
ef:70:1b:2c:4e:9c:08:ca:1d:eb:97:11:74:14:bb:99
|
||||||
fa:be:44:60:58:94:4a:9c:ba:64:1d:86:27:8b:7f:51
|
de:22:a1:6e:bc:6c:c6:25:98:8a:8e:17:f4:f9:4d:a3
|
||||||
4d:80:b0:ff:7a:91:c0:4d:a4:aa:d1:f1:79:7d:8f:71
|
1d:01:5e:26:0e:b4:e8:1c:aa:06:7c:66:b1:89:5a:b4
|
||||||
49:12:73:d4:44:5f:0c:2e:55:a6:d9:13:b8:3b:e5:dc
|
82:65:d1:bf:20:cb:b2:57:a8:af:7f:00:07:00:7c:5e
|
||||||
e1:14:98:7e:eb:5b:60:ad:d7:4b:da:c0:d8:3f:bf:70
|
d4:09:60:0c:0a:6e:a8:e1:16:1b:04:95:b1:bc:2b:35
|
||||||
92:53:8c:31:6a:8b:61:5e:a3:7d:ff:84:2c:7d:ed:9f
|
ad:80:78:0a:0a:1d:5f:c9:cc:24:3a:5e:20:03:50:44
|
||||||
74:29:9a:e7:14:fb:c3:ab:8e:9f:60:6a:98:ab:86:0b
|
b8:b0:f3:f1:17:ff:41:b8:5d:56:9b:1c:f1:e6:2b:c6
|
||||||
ea:fb:ff:20:2f:3b:a7:76:03:3a:55:bb:b2:c6:9c:b5
|
ba:a2:8c:18:25:8c:d5:90:f1:28:66:29:bb:40:3d:b2
|
||||||
66:36:b8:1c:7f:9b:b6:62:89:ff:6a:d6:35:58:0b:f0
|
f9:65:99:2e:b7:1b:e3:d0:d2:1a:d7:96:70:cc:f6:74
|
||||||
55:27:01:f0:67:8d:88:3f:74:48:3d:bf:8c:fc:05:62
|
c5:2e:bf:f5:c9:60:c0:ff:38:f8:a8:db:1a:7d:6a:4e
|
||||||
47:
|
|
||||||
|
|
||||||
exp1:
|
exp1:
|
||||||
00:99:16:2d:91:dd:a4:ac:8a:9e:68:27:f8:89:c4:38
|
5c:1b:49:f7:f9:0b:23:04:c8:2f:a6:db:dd:de:f8:f3
|
||||||
93:a6:a0:e7:f3:1a:fd:35:76:b1:f6:64:16:3d:37:e5
|
75:63:ea:72:5d:cc:21:90:5e:8b:3d:45:f0:71:ea:ad
|
||||||
88:bc:c8:d8:c8:6a:f4:fc:26:fa:38:88:42:b0:92:1b
|
d8:d8:61:a8:52:0a:39:13:6b:34:e5:c5:12:2e:60:68
|
||||||
80:b8:80:f5:c7:f9:e2:5f:c8:42:60:bf:9b:81:43:c6
|
8a:b1:79:6a:74:d6:57:5b:47:e1:63:56:d4:ac:29:07
|
||||||
5c:58:55:68:a2:c8:b1:e1:6f:07:f2:6f:e1:d4:2b:21
|
30:57:e7:98:9a:84:94:ac:66:ea:c1:24:d5:ef:e4:c5
|
||||||
bf:b3:a7:da:c5:ee:1f:63:79:1a:b7:ea:bc:36:72:73
|
e4:c1:20:13:9e:1b:c0:d6:c9:ef:e0:00:36:2f:dd:83
|
||||||
e1:8a:27:ae:a4:db:49:7c:e2:2d:60:a5:27:20:86:b3
|
a5:ef:8b:40:0c:a3:a4:60:04:2c:c2:32:95:14:69:db
|
||||||
c0:ee:6b:7a:16:6f:ff:55:a8:ee:bf:ce:67:90:5d:1e
|
43:e8:43:cc:f6:f3:44:1b:b2:03:cf:8c:5b:df:ff:4f
|
||||||
80:9b:e6:ca:1f:fd:30:c9:e2:9c:d7:62:5b:a7:b2:29
|
9b:b6:0f:25:0f:09:df:d6:5b:93:64:54:f9:3b:34:3d
|
||||||
b5:ff:78:06:00:1f:16:e8:6a:ed:2c:8f:f4:5f:97:ab
|
89:7d:83:f3:e1:c6:da:03:1f:b3:f5:0c:30:10:a3:ff
|
||||||
9e:2b:a7:56:18:e7:e9:6a:4e:b2:8c:63:76:be:26:b6
|
cd:cf:9d:bf:52:db:8f:d9:67:b0:a2:8f:94:97:d3:fe
|
||||||
6a:1c:88:31:40:65:d0:ce:b1:68:50:47:85:dd:33:a0
|
49:60:28:39:13:74:97:26:ce:28:10:b1:78:04:76:69
|
||||||
a9:
|
|
||||||
|
|
||||||
exp2:
|
exp2:
|
||||||
00:8d:b1:5f:7c:94:ed:62:39:40:b6:a9:a1:cc:02:80
|
6e:6d:c5:d5:b3:8a:aa:dd:9c:e6:5e:e6:0d:fd:20:48
|
||||||
c5:77:d6:9e:19:dd:79:4d:11:61:6a:79:8e:4d:92:de
|
85:1d:62:da:47:8c:1a:8d:2f:2e:b8:da:51:15:dd:54
|
||||||
bb:53:0b:3c:52:02:d5:69:3c:7d:95:1b:dc:51:2d:00
|
7c:eb:ab:49:80:6d:39:32:e7:e6:4f:2a:2d:6a:20:43
|
||||||
00:35:0a:b4:92:5a:74:c4:5f:b0:c0:02:9f:cc:2c:a5
|
02:35:26:c4:91:76:d6:b8:e8:31:2d:57:00:5d:15:f5
|
||||||
29:08:93:25:9a:c5:ba:1a:a1:7a:7e:15:5e:ff:e3:ea
|
a0:82:55:27:3b:88:dc:0c:c6:e1:19:87:b5:f5:03:9b
|
||||||
07:8e:85:a2:c9:60:7f:40:bb:2c:a8:6f:0e:85:ab:a0
|
b8:36:ae:ff:bf:50:d8:63:63:34:df:3d:11:a1:ff:d3
|
||||||
0f:b5:b0:70:1b:fe:1f:eb:66:78:fb:60:ef:71:de:40
|
ed:41:ed:0b:f9:df:a4:de:19:fb:18:ae:70:6d:88:08
|
||||||
d9:de:cb:d9:16:40:52:12:2c:3a:b7:5a:63:fc:54:18
|
0d:95:02:a1:5c:be:7d:55:eb:74:75:d2:cb:bd:5a:05
|
||||||
e2:05:bd:d7:68:ae:b4:98:d2:2f:1c:36:13:46:5b:25
|
23:12:d9:0e:ec:50:88:f4:07:1c:e3:1c:5e:f4:cd:69
|
||||||
31:f1:28:eb:32:c3:b1:2b:e9:e4:6f:99:cd:6d:d4:80
|
97:46:97:30:a8:3c:ea:ad:72:db:de:fc:35:cc:b4:d1
|
||||||
3a:5d:d0:3c:18:93:b7:2c:4e:0e:fe:b1:1c:97:ba:b1
|
25:0d:3b:d0:86:27:18:f6:02:37:28:c9:64:b9:86:31
|
||||||
61:72:68:eb:6e:60:62:a5:81:b0:21:33:0a:cc:1b:a8
|
98:58:41:13:c8:26:4b:d6:f7:a1:8d:fe:6e:e0:76:ff
|
||||||
5b:
|
|
||||||
|
|
||||||
|
|
||||||
Public Key PIN:
|
Public Key PIN:
|
||||||
pin-sha256:iFdBnKP/7hZCLdj7qqTtdNPFjpZGka259fSYvv3X02U=
|
pin-sha256:Zv2mSFRUYM7ofg5obMJJxhZpnuvO7gkCOlqfDK1gzks=
|
||||||
Public Key ID:
|
Public Key ID:
|
||||||
sha256:8857419ca3ffee16422dd8fbaaa4ed74d3c58e964691adb9f5f498befdd7d365
|
sha256:66fda648545460cee87e0e686cc249c616699eebceee09023a5a9f0cad60ce4b
|
||||||
sha1:aac584e0e34ca0a8a5bf9641adbd3ec1d1e075e0
|
sha1:155a6bfa2fc8fa5b93ff27966b88496076fedf31
|
||||||
|
|
||||||
-----BEGIN RSA PRIVATE KEY-----
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
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
|
||||||
-----END RSA PRIVATE KEY-----
|
-----END RSA PRIVATE KEY-----
|
||||||
|
|
|
||||||
37
internal/misc/json.go
Normal file
37
internal/misc/json.go
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
@ -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
|
package misc //revive:disable-line:var-naming
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
|
||||||
21
internal/misc/url.go
Normal file
21
internal/misc/url.go
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
@ -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.Errorf(testTimeRange.UnmarshalText(byteSlice).Error())
|
t.Error(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.Errorf(err.Error())
|
t.Error(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.Errorf(err.Error())
|
t.Error(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.Errorf(err.Error())
|
t.Error(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ 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)
|
||||||
|
|
@ -82,6 +81,7 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.Fatalf(err.Error())
|
t.Fatal(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.Fatalf(err.Error())
|
t.Fatal(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.Errorf(err.Error())
|
t.Error(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
171
testdata/csaf-documents/trailing-garbage-data/avendor-advisory-0004.json
vendored
Normal file
171
testdata/csaf-documents/trailing-garbage-data/avendor-advisory-0004.json
vendored
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
{
|
||||||
|
"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
|
||||||
169
testdata/csaf-documents/valid/advisory-tracking-generator-no-version.json
vendored
Normal file
169
testdata/csaf-documents/valid/advisory-tracking-generator-no-version.json
vendored
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
{
|
||||||
|
"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"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
170
testdata/csaf-documents/valid/avendor-advisory-0004.json
vendored
Normal file
170
testdata/csaf-documents/valid/avendor-advisory-0004.json
vendored
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
{
|
||||||
|
"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"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -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
|
package util //revive:disable-line:var-naming
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
|
||||||
|
|
@ -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
|
package util //revive:disable-line:var-naming
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
|
|
||||||
|
|
@ -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
|
package util //revive:disable-line:var-naming
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|
|
||||||
|
|
@ -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
|
package util //revive:disable-line:var-naming
|
||||||
|
|
||||||
// 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{}
|
||||||
|
|
|
||||||
|
|
@ -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
|
package util //revive:disable-line:var-naming
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue