1
0
Fork 0
mirror of https://github.com/gocsaf/csaf.git synced 2025-12-22 05:40:11 +01:00

Compare commits

...

87 commits
v3.2.0 ... main

Author SHA1 Message Date
Sascha L. Teichmann
586524a97e
Update 3rd party libraries. (#711)
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
2025-12-18 13:25:44 +01:00
Benjamin Grandfond
52ce6bcde6
fix: engine is invalid when name is missing (#710)
Some checks failed
generate-markdown / auto-update-readme (push) Waiting to run
Go Test (oldstable) / build (push) Has been cancelled
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
2025-12-18 12:50:37 +01:00
JanHoefelmeyer
9393271699
Merge pull request #703 from gocsaf/add_rolie_category
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
Go Test (oldstable) / build (push) Has been cancelled
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
ROLIE: Add category to entries
2025-12-01 07:14:49 +01:00
JanHoefelmeyer
0630a9a64a
Merge pull request #706 from gocsaf/3rdparty_updates_2025_11_28
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
Update 3rd party libraries
2025-11-28 16:14:48 +01:00
JanHoefelmeyer
502376ce3a fix typo: contibutor -> contributor
Some checks failed
Go Test (oldstable) / build (push) Has been cancelled
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
2025-11-28 16:12:10 +01:00
Sascha L. Teichmann
c678a97d43 Update 3rd party libraries 2025-11-28 11:03:29 +01:00
Sascha L. Teichmann
9a37a8ecfa Add more fields to rolie entry.
Some checks are pending
Go Test (oldstable) / build (push) Waiting to run
Go / build (push) Waiting to run
Go / run_modver (push) Blocked by required conditions
2025-11-27 15:23:34 +01:00
Sascha L. Teichmann
d6bac95e45 Removed debugging code 2025-11-19 12:56:04 +01:00
Sascha L. Teichmann
5a1c2a0873 Add category field to ROLIE feed model. 2025-11-19 12:12:43 +01:00
JanHoefelmeyer
8dd4cb4fa8
Merge pull request #696 from gocsaf/slient-revive
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
Go Test (oldstable) / build (push) Has been cancelled
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
silence revive linter warnings
2025-10-27 11:07:06 +01:00
Christoph Klassen
9607f8db94
fix: Documentation about supported options (#697) 2025-10-27 10:38:22 +01:00
Bernhard E. Reiter
46118544be
upgrade dependencies, including go (#695)
* change go.mod as first step towards go 1.25

  raise minium version of go compatiblity to 1.24.9
  and toolchain to be used to 1.25.3

* upgrade .github/workflows and documentation

  * update all .github/workflows/ to use the latest version of
    actions and the go versions accordingly.
    (Only some github actions use a floating tag for the major version.)
  * reduce places where the go versions are hardcoded:
      * refEr to docs/Development.md from README.md
      * use `go.mod` from itest.yml.

* fix itest.yml: checkout before refer to go.mod

* improve code cleanness: use format string w error

  and thus makes newer go test versions happy

* update go dependencies

* cleanup some dependencies with go mod tidy

* fix .github/workflows action versions

* fix go action versions
2025-10-27 10:35:38 +01:00
Bernhard Reiter
fb59a40609
fix code formatting 2025-10-23 16:19:13 +02:00
Bernhard Reiter
cf9c62fcc0
silence revive linter warnings
that we cannot or do not want to fix yet
2025-10-23 16:09:18 +02:00
Bernhard Reiter
b6281012f5
fix go action versions 2025-10-23 14:15:32 +02:00
Bernhard Reiter
8740244dd8
fix .github/workflows action versions 2025-10-23 14:12:16 +02:00
Bernhard Reiter
6cc1d7a38f
cleanup some dependencies with go mod tidy 2025-10-23 13:55:14 +02:00
Bernhard Reiter
ffb1a31944
update go dependencies 2025-10-23 13:22:37 +02:00
Bernhard Reiter
ef44c92f8b
improve code cleanness: use format string w error
and thus makes newer go test versions happy
2025-10-23 13:17:28 +02:00
Bernhard Reiter
223570ac9b
fix itest.yml: checkout before refer to go.mod 2025-10-23 13:00:33 +02:00
Bernhard Reiter
fc012fa820
upgrade .github/workflows and documentation
* update all .github/workflows/ to use the latest version of
    actions and the go versions accordingly.
    (Only some github actions use a floating tag for the major version.)
  * reduce places where the go versions are hardcoded:
      * refEr to docs/Development.md from README.md
      * use `go.mod` from itest.yml.
2025-10-23 12:42:36 +02:00
Bernhard Reiter
f046ade489
change go.mod as first step towards go 1.25
raise minium version of go compatiblity to 1.24.9
  and toolchain to be used to 1.25.3
2025-10-23 12:09:41 +02:00
Bernhard E. Reiter
c6bad42c24
Improve LoadCertificate unit test (#692)
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
Go Test (oldstable) / build (push) Has been cancelled
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
* fix `LoadCertificate` unit test

replaced certificate with invalid dns name, which is rejected by stdlib of Go version >=1.25.2.

Change in Go introduced by https://github.com/golang/go/issues/75715

* code review: add script to generate certificates, remove `greenbone` org entry

* code review: add license header

* rework cert creation and fix one filename

---------

Co-authored-by: Marius Goetze <marius.goetze@greenbone.net>
2025-10-22 16:57:00 +02:00
JanHoefelmeyer
05eae0a9ae
Re-add unknown fields check (#681)
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
Go Test (oldstable) / build (push) Has been cancelled
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
2025-10-01 11:14:09 +02:00
Christoph Klassen
e3d2a58528
Merge pull request #680 from gocsaf/better-workflow-name
Rename workflow go_legacy to "Go Test (oldstable)"
2025-10-01 10:59:44 +02:00
JanHoefelmeyer
04955d6fad
Merge pull request #678 from greenbone/fix-formatted-string-upstream
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
fix incorrect usage of formatted string
2025-09-22 17:04:02 +02:00
mgoetzegb
0dbf822cbd
fix doc comment: remove untrue claim of disallowing unknown fields (#677)
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
adjust comment to fit 7935818600
2025-09-15 12:42:30 +02:00
Bernhard Reiter
bcb7c8be10
rename go_legacy.yml -> go-oldstable.yml 2025-09-12 11:41:13 +02:00
Bernhard E. Reiter
5c1b061255
Rename workflow go_legacy to "Go Test (oldstable)"
so it is distinct from the other "Go" workflow
2025-09-12 11:38:56 +02:00
Marius Goetze
d1f33ab27d fix incorrect usage of formatted string
output probably unchanged, but now `go vet` is happy that formatted strings are not misused
2025-09-08 13:19:15 +02:00
Paul Schwabauer
187d114631
Remove unnecessary URL joins (#676)
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
This should avoid bugs for more complex scenarios.
2025-09-01 16:13:57 +02:00
Bernhard E. Reiter
1a2a8fae9c
improve docs (minor) for csaf_provider (#668)
Some checks are pending
generate-markdown / auto-update-readme (push) Waiting to run
Go / build (push) Waiting to run
Go / run_modver (push) Blocked by required conditions
* add a "both" to explain the config file option
    `certificate_and_password` better.
2025-09-01 15:40:42 +02:00
Bernhard E. Reiter
f6927154bf
improve calculated version numbers (#651)
for modified git workspaces a `-modified` is added to the semantic version
  in the makefile.
2025-09-01 15:40:26 +02:00
Paul Schwabauer
1f1a2a4cbc
Add arm64 builds for windows and linux (#663) 2025-09-01 12:04:17 +02:00
JanHoefelmeyer
fa8370bd60
Merge pull request #675 from gocsaf/doc18
improve docs/csaf_downloader.md (minor) time_range
2025-09-01 11:53:15 +02:00
JanHoefelmeyer
7ab964a3e3
Doc: Highlight the reason for the rate options existence (#662)
* Doc: Highlight the reason for the rate options existence

* Fix typos
2025-09-01 11:48:56 +02:00
JanHoefelmeyer
c7a284bf7f
Merge pull request #667 from gocsaf/docs-10
fix minor docs typo
2025-09-01 11:45:37 +02:00
Christoph Klassen
08ab318545
Merge pull request #674 from gocsaf/fix-listing-check
Fix csaf checker listed check
2025-09-01 11:15:24 +02:00
Christoph Klassen
a2fab16d3b
Merge pull request #671 from gocsaf/fix-create-error-handling
Fix #669
2025-09-01 11:13:56 +02:00
Bernhard Reiter
108e5f8620
improve docs/csaf_downloader.md (minor) time_range 2025-08-26 15:24:51 +02:00
koplas
100e4d395b Fix csaf checker listed check
Correctly handle URLs that are absolute.
2025-08-26 11:58:49 +02:00
koplas
7fc5600521
Fix #669
Some checks failed
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
Return error when the create request failed.
2025-08-11 08:50:02 +02:00
Sebastian Wagner
7f27a63e3c
docs provider-setup.md: Fix create URL in curl command
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
2025-08-01 11:42:52 +02:00
Bernhard Reiter
230e9f2d2b
fix minor docs typo 2025-07-31 11:29:44 +02:00
JanHoefelmeyer
ae184eb189
Merge pull request #655 from gocsaf/json-eof
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
Make json parsing more strict
2025-07-08 07:46:07 +02:00
JanHoefelmeyer
4b4d6ed594 Remove uknown field tests
Some checks failed
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
2025-07-07 11:45:36 +02:00
JanHoefelmeyer
7935818600 Fix: Allow unknown fields: They are not forbidden 2025-07-07 11:41:49 +02:00
koplas
c81f55a752
Add LoadAdvisory tests
Some checks failed
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
2025-07-04 15:29:03 +02:00
JanHoefelmeyer
e7c08d05cd Rewrite function from scratch
Some checks failed
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
2025-07-03 11:03:06 +02:00
koplas
fc3837d655
Make json parsing more strict
Some checks are pending
Go / build (push) Waiting to run
Go / run_modver (push) Blocked by required conditions
2025-07-02 17:06:25 +02:00
Christoph Klassen
dad4e54184
Merge pull request #659 from gocsaf/fix-checker-join
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
Fix checker url base handling
2025-07-02 16:34:13 +02:00
koplas
01c43d96ce
Fix checker url base handling 2025-07-02 16:27:58 +02:00
Christoph Klassen
ca54ba53be
Merge pull request #658 from gocsaf/fix-agg-join
Fix aggregator url base handling
2025-07-02 15:53:33 +02:00
koplas
3262e2ec2a
Fix aggregator url base handling 2025-07-02 15:33:37 +02:00
Christoph Klassen
bcd34d9fba
Merge pull request #653 from gocsaf/top-level-docs
Some checks are pending
generate-markdown / auto-update-readme (push) Waiting to run
Go / build (push) Waiting to run
Go / run_modver (push) Blocked by required conditions
docs: improve README.md
2025-07-02 09:38:22 +02:00
Christoph Klassen
5fd5076f52
Merge pull request #656 from gocsaf/warn-config
Print warning if no config file was found
2025-07-02 09:33:58 +02:00
JanHoefelmeyer
21ce19735b Fix: Fix typo and misleading meaning 2025-07-02 09:23:23 +02:00
JanHoefelmeyer
27e9519ed5 Fix: Remove some Typos as well as grammatical errors and oddities 2025-07-02 09:20:27 +02:00
koplas
a7b1291be8
Print warning if no config file was found 2025-06-27 17:20:19 +02:00
Bernhard Reiter
7b7d0c4dcb
improve phrasing
Some checks failed
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
2025-06-27 10:24:48 +02:00
Bernhard Reiter
a6d0a0c790
docs: extend package csaf doc comment
* fix sentence.
  * add link to the section in the top-level readme that has the limits
    on the use as a library.
2025-06-27 10:20:56 +02:00
Bernhard Reiter
d54e211ef3
docs: improve README.md
* Deemphazise the old repo link alert.
 * Add more hints about officially unsupported but possible use as
   library.

solve #634
2025-06-27 09:49:32 +02:00
Christoph Klassen
c833c00f84
Merge pull request #649 from gocsaf/url-join
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
Use JoinPath
2025-06-26 08:18:39 +02:00
Christoph Klassen
4066704c1a
Merge pull request #633 from gocsaf/check-prefix-url
Some checks are pending
generate-markdown / auto-update-readme (push) Waiting to run
Go / build (push) Waiting to run
Go / run_modver (push) Blocked by required conditions
Check if canonical url prefix is valid
2025-06-25 17:05:09 +02:00
Christoph Klassen
f154b78340
Merge pull request #652 from gocsaf/less_bloat
Feat: More explicitely handle which doc files are included in the dist
2025-06-25 15:37:45 +02:00
JanHoefelmeyer
d5778f0755
Merge pull request #647 from gocsaf/pmd-diagnostic
csaf_checker: Always generate report
2025-06-25 15:33:47 +02:00
JanHoefelmeyer
5d37dd1339 Move PMD error from logs to report.
Some checks failed
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
2025-06-25 09:31:50 +02:00
JanHoefelmeyer
d09db6635d Fix: Assume most restrictive role to prevent false-positives
Some checks are pending
Go / build (push) Waiting to run
Go / run_modver (push) Blocked by required conditions
2025-06-24 17:24:08 +02:00
koplas
3f4fe5cf18
Also generate report when role is not available 2025-06-24 17:18:42 +02:00
JanHoefelmeyer
02d4931152 Fix: Return properly early 2025-06-24 17:06:55 +02:00
JanHoefelmeyer
9c62e89a23 Feat: More explicitely handle which doc files are included in the gnulinux dist 2025-06-24 14:34:44 +02:00
Christoph Klassen
062e145761
Merge pull request #650 from gocsaf/write-version
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
Use folder name as version if git describe failed
2025-06-24 10:48:11 +02:00
koplas
36aab33de4 Use folder name as version if git describe failed 2025-06-20 16:50:13 +02:00
koplas
1098c6add0 Use correct base URL
Some checks failed
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
2025-06-20 16:37:37 +02:00
koplas
091854a248 Always generate report
Some checks failed
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
Closes #385
2025-06-20 14:24:05 +02:00
Christoph Klassen
ce886f138a
Merge pull request #648 from gocsaf/update-modver
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
Update modver
2025-06-20 08:59:50 +02:00
koplas
6ac97810d0
Use JoinPath
This avoids issues where parts of the URL are discarded.
2025-06-19 15:11:45 +02:00
koplas
cb291bb81b
Update modver 2025-06-19 14:39:02 +02:00
Christoph Klassen
12cde3aa3c
Merge pull request #637 from gocsaf/api-break-action
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
Go / build (push) Has been cancelled
Go / run_modver (push) Has been cancelled
Add semver breaking changes detection
2025-06-18 09:04:37 +02:00
Christoph Klassen
fa1861385a
Merge pull request #643 from gocsaf/jsonschema-upgrade
Upgrade jsonschema to v6
2025-06-18 08:51:06 +02:00
koplas
dcdbc5d49d
Add semver breaking changes detection 2025-06-13 18:50:57 +02:00
koplas
34705f3c6e Address comments
Some checks failed
Go / build (push) Has been cancelled
2025-06-13 11:01:43 +02:00
koplas
6955c4e37c Upgrade node.js and format workflow file 2025-06-13 10:19:21 +02:00
koplas
fc64bf7165
Upgrade jsonschema to v6 2025-06-12 15:53:39 +02:00
JanHoefelmeyer
161ec1f15c
Merge pull request #635 from gocsaf/remove-golint-action
Some checks failed
generate-markdown / auto-update-readme (push) Has been cancelled
Remove golint github action
2025-06-10 07:45:56 +02:00
Christoph Klassen
3ab00e8759
Remove golint github action
We use Revive already which is a replacement for golint and golint isn't maintained anyway.
2025-05-28 11:30:46 +02:00
koplas
91b5b4543e
Check if canonical url prefix is valid 2025-04-03 14:41:14 +02:00
56 changed files with 1399 additions and 575 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -12,15 +12,15 @@ SHELL = /bin/bash
BUILD = go build
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:
@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 or set BUILDTAG to a specific tag
# 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
ifeq ($(strip $(BUILDTAG)),1)
@ -29,7 +29,7 @@ endif
ifdef BUILDTAG
# 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
tag_checked_out:
@ -47,13 +47,18 @@ tag_checked_out:
# 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")`
# 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/')
SEMVERPATCH := $(shell echo $$(( $(GITDESCPATCH) + 1 )))
# Hint: The second regexp in the next line only matches
# if there is a hyphen (`-`) followed by a number,
# 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/' )
endif
testsemver:
@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)
# Using 'Target-specific Variable Values' to specify the build target system
GOARCH = amd64
build_linux: GOOS = linux
build_win: GOOS = windows
build_mac_amd64: GOOS = darwin
build_linux: GOOS=linux
build_linux: GOARCH=amd64
build_mac_arm64: GOARCH = arm64
build_mac_arm64: GOOS = darwin
build_win: GOOS=windows
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)/ )
$(MKDIR) $(BINDIR)
env GOARCH=$(GOARCH) GOOS=$(GOOS) $(BUILD) -o $(BINDIR) $(LDFLAGS) -v ./cmd/...
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/$(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-arm64
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 \
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-arm64/docs
cp docs/csaf_uploader.md docs/csaf_validator.md docs/csaf_checker.md \
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 \
dist/$(DISTDIR)-macos/bin-darwin-arm64 \
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 ; \
done
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-arm64.zip $(DISTDIR)-windows-arm64/
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
# Remove bin-*-* and dist directories

View file

@ -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
@ -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)
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)
are small examples of how to use `github.com/gocsaf/csaf`
as an API. Currently this is a work in progress, as usage of this repository
as a library to access is _not officially supported_, e.g.
see https://github.com/gocsaf/csaf/issues/367 .
are small examples of how to use `github.com/gocsaf/csaf` as an API. Currently this is a work in progress.
## Setup
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
- 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 `
@ -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).
## 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

View file

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

View file

@ -13,7 +13,6 @@ import (
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"log/slog"
@ -31,6 +30,7 @@ import (
"github.com/ProtonMail/gopenpgp/v2/crypto"
"github.com/gocsaf/csaf/v3/csaf"
"github.com/gocsaf/csaf/v3/internal/misc"
"github.com/gocsaf/csaf/v3/util"
)
@ -67,7 +67,7 @@ func (w *worker) mirrorInternal() (*csaf.AggregatorCSAFProvider, error) {
// Collecting the categories per label.
w.categories = map[string]util.Set[string]{}
base, err := url.Parse(w.loc)
pmdURL, err := url.Parse(w.loc)
if err != nil {
return nil, err
}
@ -76,7 +76,7 @@ func (w *worker) mirrorInternal() (*csaf.AggregatorCSAFProvider, error) {
w.client,
w.expr,
w.metadataProvider,
base)
pmdURL)
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 {
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 {
@ -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.
func (w *worker) downloadSignatureOrSign(url, fname string, data []byte) error {
sig, err := w.downloadSignature(url)
if err != nil {
if err != errNotFound {
w.log.Error("Could not find signature URL", "url", url, "err", err)

View file

@ -13,6 +13,8 @@ import (
"net/http"
"net/url"
"github.com/gocsaf/csaf/v3/internal/misc"
"github.com/PuerkitoBio/goquery"
"github.com/gocsaf/csaf/v3/util"
@ -93,7 +95,12 @@ func (pgs pages) listed(
return err
}
// 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)
return nil
})

View file

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

View file

@ -216,11 +216,6 @@ func defaults[T any](p *T, def T) T {
// processROLIEFeeds goes through all ROLIE feeds and checks their
// integrity and completeness.
func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
base, err := url.Parse(p.pmdURL)
if err != nil {
return err
}
p.badROLIEFeed.use()
advisories := map[*csaf.Feed][]csaf.AdvisoryFile{}
@ -232,12 +227,11 @@ func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
if feed.URL == nil {
continue
}
up, err := url.Parse(string(*feed.URL))
feedBase, err := url.Parse(string(*feed.URL))
if err != nil {
p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err)
continue
}
feedBase := base.ResolveReference(up)
feedURL := feedBase.String()
p.checkTLS(feedURL)
@ -264,13 +258,12 @@ func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
continue
}
up, err := url.Parse(string(*feed.URL))
feedURL, err := url.Parse(string(*feed.URL))
if err != nil {
p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err)
continue
}
feedURL := base.ResolveReference(up)
feedBase, err := util.BaseURL(feedURL)
if err != nil {
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
// 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 {
return err
}
@ -319,13 +312,12 @@ func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
continue
}
up, err := url.Parse(string(*feed.URL))
feedBase, err := url.Parse(string(*feed.URL))
if err != nil {
p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err)
continue
}
feedBase := base.ResolveReference(up)
makeAbs := makeAbsolute(feedBase)
label := defaults(feed.TLPLabel, csaf.TLPLabelUnlabeled)

View file

@ -35,6 +35,7 @@ import (
"golang.org/x/time/rate"
"github.com/gocsaf/csaf/v3/csaf"
"github.com/gocsaf/csaf/v3/internal/misc"
"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 {
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(
client,
lpmd.Document,
base,
expr,
); err != nil {
return err
@ -245,7 +245,7 @@ func (d *downloader) download(ctx context.Context, domain string) error {
client,
expr,
lpmd.Document,
base)
pmdURL)
// Do we need time range based filtering?
if d.cfg.Range != nil {
@ -310,7 +310,6 @@ allFiles:
func (d *downloader) loadOpenPGPKeys(
client util.Client,
doc any,
base *url.URL,
expr *util.PathEval,
) error {
src, err := expr.Eval("$.public_openpgp_keys", doc)
@ -335,7 +334,7 @@ func (d *downloader) loadOpenPGPKeys(
if key.URL == nil {
continue
}
up, err := url.Parse(*key.URL)
u, err := url.Parse(*key.URL)
if err != nil {
slog.Warn("Invalid URL",
"url", *key.URL,
@ -343,9 +342,7 @@ func (d *downloader) loadOpenPGPKeys(
continue
}
u := base.ResolveReference(up).String()
res, err := client.Get(u)
res, err := client.Get(u.String())
if err != nil {
slog.Warn(
"Fetching public OpenPGP key failed",
@ -550,7 +547,7 @@ func (dc *downloadContext) downloadAdvisory(
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++
slog.Warn("Downloading failed",
"url", file.URL(),

View file

@ -11,6 +11,7 @@ package main
import (
"fmt"
"io"
"net/url"
"os"
"strings"
@ -262,6 +263,14 @@ func loadConfig() (*config, error) {
if cfg.CanonicalURLPrefix == "" {
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 {
cfg.TLPs = []tlp{tlpCSAF, tlpWhite, tlpGreen, tlpAmber, tlpRed}

View file

@ -11,7 +11,6 @@ package main
import (
"bytes"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
@ -82,8 +81,9 @@ func (p *processor) create() error {
}
defer resp.Body.Close()
var createError error
if resp.StatusCode != http.StatusOK {
log.Printf("Create failed: %s\n", resp.Status)
createError = fmt.Errorf("create failed: %s", resp.Status)
}
var result struct {
@ -91,7 +91,7 @@ func (p *processor) create() error {
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
}
@ -101,7 +101,7 @@ func (p *processor) create() error {
writeStrings("Errors:", result.Errors)
return nil
return createError
}
// 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 {
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
}
errs, err := csaf.ValidateCSAF(doc)
@ -239,7 +239,7 @@ func (p *processor) process(filename string) error {
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
}

View file

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

View file

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

View file

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

46
csaf/advisory_test.go Normal file
View 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)
}
})
}
}

View file

@ -6,7 +6,11 @@
// SPDX-FileCopyrightText: 2023 German Federal Office for Information Security (BSI) <https://www.bsi.bund.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
//go:generate go run ./generate_cvss_enums.go -o cvss20enums.go -i ./schema/cvss-v2.0.json -p CVSS20

View file

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

View file

@ -17,6 +17,7 @@ import (
"strings"
"time"
"github.com/gocsaf/csaf/v3/internal/misc"
"github.com/gocsaf/csaf/v3/util"
)
@ -575,7 +576,6 @@ func (d *Distribution) Validate() error {
// Validate checks if the provider metadata is valid.
// Returns an error if the validation fails otherwise nil.
func (pmd *ProviderMetadata) Validate() error {
switch {
case pmd.CanonicalURL == nil:
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) {
var pmd ProviderMetadata
dec := json.NewDecoder(r)
if err := dec.Decode(&pmd); err != nil {
if err := misc.StrictJSONParse(r, &pmd); err != nil {
return nil, err
}

View file

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

View file

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

View file

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

View file

@ -10,13 +10,17 @@ package csaf
import (
"bytes"
"crypto/tls"
_ "embed" // Used for embedding.
"io"
"errors"
"fmt"
"net/http"
"sort"
"strings"
"sync"
"time"
"github.com/santhosh-tekuri/jsonschema/v5"
"github.com/santhosh-tekuri/jsonschema/v6"
)
//go:embed schema/csaf_json_schema.json
@ -64,13 +68,28 @@ var (
compiledRolieSchema = compiledSchema{url: rolieSchemaURL}
)
// loadURL loads the content of an URL from embedded data or
// falls back to the global loader function of the jsonschema package.
func loadURL(s string) (io.ReadCloser, error) {
loader := func(data []byte) (io.ReadCloser, error) {
return io.NopCloser(bytes.NewReader(data)), nil
type schemaLoader http.Client
func (l *schemaLoader) loadHTTPURL(url string) (any, error) {
client := (*http.Client)(l)
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:
return loader(csafSchema)
case cvss20SchemaURL:
@ -86,14 +105,27 @@ func loadURL(s string) (io.ReadCloser, error) {
case rolieSchemaURL:
return loader(rolieSchema)
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() {
c := jsonschema.NewCompiler()
c.AssertFormat = true
c.LoadURL = loadURL
c.AssertFormat()
c.UseLoader(newSchemaLoader(false))
cs.compiled, cs.err = c.Compile(cs.url)
}
@ -109,7 +141,8 @@ func (cs *compiledSchema) validate(doc any) ([]string, error) {
return nil, nil
}
valErr, ok := err.(*jsonschema.ValidationError)
var valErr *jsonschema.ValidationError
ok := errors.As(err, &valErr)
if !ok {
return nil, err
}
@ -133,21 +166,21 @@ func (cs *compiledSchema) validate(doc any) ([]string, error) {
if 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))
for i := range errs {
e := &errs[i]
if e.Error == "" {
if e.Error == nil {
continue
}
loc := e.InstanceLocation
if loc == "" {
loc = e.AbsoluteKeywordLocation
}
res = append(res, loc+": "+e.Error)
res = append(res, loc+": "+e.Error.String())
}
return res, nil

View file

@ -3,7 +3,7 @@
## Supported Go versions
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

View file

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

View file

@ -78,6 +78,13 @@ The option `timerange` allows to only check advisories from a given time
interval. It can only be given once. See the
[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
of regular expressions[^1] to match their URLs by using the `ignorepattern`
option.

View file

@ -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
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:
```
@ -69,7 +75,7 @@ insecure = false
# client_cert # not set by default
# client_key # not set by default
# client_passphrase # not set by default
ignoresigcheck = false
ignore_sigcheck = false
# rate # set to unlimited
worker = 2
# time_range # not set by default
@ -104,8 +110,9 @@ ignorepattern = [".*white.*", ".*red.*"]
#### Timerange option
The `timerange` parameter enables downloading advisories which last changes falls
into a given intervall. There are three possible notations:
The `time_range` parameter enables downloading advisories
which last changes falls into a given intervall.
There are three possible notations:
1. Relative. If the given string follows the rules of a
[Go duration](https://pkg.go.dev/time@go1.20.6#ParseDuration),

View file

@ -58,7 +58,8 @@ The following example file documents all available configuration options:
# The following shows an example of a manually set prefix:
#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
# Allow the user to send the request without having to send a passphrase

View file

@ -144,7 +144,7 @@ on a GNU/Linux operating system.
Create the folders:
```(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
in pkcs12 format which includes the corresponding key as well.

View file

@ -1,5 +1,5 @@
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.
@ -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)
- `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):
``` bash

34
go.mod
View file

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

114
go.sum
View file

@ -1,28 +1,30 @@
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
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/go.mod h1:xmGyGpP5be12EL0P12h+dqiYG8qn2j3PJxIgkoOHO5o=
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/ProtonMail/go-crypto v1.1.2 h1:A7JbD57ThNqh7XjmHE+PXpQ3Dqt3BrSAC0AL0Go3KS0=
github.com/ProtonMail/go-crypto v1.1.2/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
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/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=
github.com/ProtonMail/gopenpgp/v2 v2.8.0 h1:WvMv3CMcFsqKSM4/Qf8sf3tgyQkzDqQmoSE49bnBuP4=
github.com/ProtonMail/gopenpgp/v2 v2.8.0/go.mod h1:qb2GUSnmA9ipBW5GVtCtEhkummSlqs2A8Ar3S0HBgSY=
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
github.com/ProtonMail/gopenpgp/v2 v2.9.0 h1:ruLzBmwe4dR1hdnrsEJ/S7psSBmV15gFttFUPP/+/kE=
github.com/ProtonMail/gopenpgp/v2 v2.9.0/go.mod h1:IldDyh9Hv1ZCCYatTuuEt1XZJ0OPjxLpTarDfglih7s=
github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw=
github.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ=
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
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/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
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.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/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
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/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
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.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
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.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
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=
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
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.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-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.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.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
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-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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
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-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-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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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-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.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
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.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.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.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.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
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-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.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=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View file

@ -20,13 +20,13 @@ func TestLoadCertificates(t *testing.T) {
passphrase = "qwer"
missingCert = "data/testclientcert_missing.crt"
missingTestkey = "data/testclientkey_missing.pem"
privateKey = "data/privated.pem"
privateKey = "data/private.pem"
privateCert = "data/cert.crt"
)
// Try to load cert that is not protected, expect success.
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.
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.
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.
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 {
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 {
t.Errorf("Failure: Expected nil return.")
t.Errorf("Failure: Expected nil return. Got error: %v", err)
}
}

View 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

View file

@ -1,37 +1,28 @@
-----BEGIN CERTIFICATE-----
MIIGajCCBNKgAwIBAgIUGNi4GgCUssOOe3k0VuHf3R0+d54wDQYJKoZIhvcNAQEL
BQAwgY0xFDASBgNVBAMTC0NvbW1vbiBuYW1lMRMwEQYDVQQLEwppbnRldmF0aW9u
MRMwEQYDVQQKEwppbnRldmF0aW9uMRMwEQYDVQQHEwppbnRldmF0aW9uMRUwEwYD
VQQIEwxMb3dlciBTYXhvbnkxCzAJBgNVBAYTAkdFMRIwEAYKCZImiZPyLGQBGRYC
REMwHhcNMjMwOTE5MDcwMDA1WhcNMjYwNjE0MDcwMDA3WjCB8DEQMA4GA1UEAxMH
cmVxdWVzdDETMBEGA1UECxMKaW50ZXZhdGlvbjETMBEGA1UEChMKaW50ZXZhdGlv
bjETMBEGA1UEBxMKb3NuYWJydWVjazEVMBMGA1UECBMMbG93ZXIgc2F4b255MQsw
CQYDVQQGEwJHRTESMBAGCgmSJomT8ixkARkWAkRDMREwDwYKCZImiZPyLGQBGRYB
LjERMA8GCgmSJomT8ixkARkWAS4xETAPBgoJkiaJk/IsZAEZFgEuMRMwEQYKCZIm
iZPyLGQBGRYDd3d3MRcwFQYKCZImiZPyLGQBARMHbm8gaWRlYTCCAaIwDQYJKoZI
hvcNAQEBBQADggGPADCCAYoCggGBAN0vZbLXtRzd61rR8Hos0BGnqCaJXIwGARwx
JojMyxASFT+KeC4QDRkgRrK6OY4k/i7TEHuUGk/Bm754++554wmmhDqv1Q4+VhhR
1K/JAz/HVZNTAR1rPKwG82lyEpPxlRNZg/QtF9DqQSoSkL/fJLs+rq4zlKozXzRE
auZ5Be8So1dXRZfMVUMDgtk+IX8+iCeZisiWfv62ttQ0EiuiXLagd6ruEuoCSVi2
tVswsC/Hp8AI2Ro56mmHiWthuae1H8yDWUFLSe9AQW65qC/xVUgo/nMpK2BYVFKb
70TMjl/dZM0Qn1tdiNyqCkbIhXjklZvZYhO+15TPkgDXDsqRUjpTrLZXLGrD6XIx
CRLZGY6YrUfsFTjUC6JrUrAR8zY7SLsYN5sUmFUSMpJnI+T/SD4p/0CXrKrbMOjW
Qqz6FX/WHPxvswGKHk5zHYGHrzx7OKmfVa6gzUgZSfOHj2xOOR2Un9DwNavIrmSC
WYXKZqig5qDyfzBvlXWEio/5GrDwgQIDAQABo4IBWzCCAVcwgcIGA1UdEQSBujCB
t4IrYSBkbnNOYW1lIG9mIHRoZSBzdWJqZWN0IG9mIHRoZSBjZXJ0aWZpY2F0ZYI3
YW4gYWRkaXRpb25hbCBkbnNOYW1lIG9mIHRoZSBzdWJqZWN0IG9mIHRoZSBjZXJ0
aWZpY2F0ZYIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIBLoIP
c2Vjb25kIGFkZGl0aW9ugg50aGlyZCBhZGRpdGlvboIHZG5zTmFtZTAMBgNVHRMB
Af8EAjAAMDEGA1UdJQQqMCgGCCsGAQUFBwMJBggrBgEFBQcDAgYIKwYBBQUHAwEG
CCsGAQUFBwMCMA8GA1UdDwEB/wQFAwMHsAAwHQYDVR0OBBYEFKrFhODjTKCopb+W
Qa29PsHR4HXgMB8GA1UdIwQYMBaAFCyZxCa1ZUHVy8LjikE8zumAiEgfMA0GCSqG
SIb3DQEBCwUAA4IBgQBTrAgh6d+qiLumEfmkNCmhewxKxDZp+Ni2nz9XRzNO2cQE
U0n8MdbnQInW3xJXng2sAcl1fQz0RN1hkyjDwi69mbbPgcTYmxJFvyt+zRYBe/Sq
4CGGkxEdPW94tMpQ6SrCn2mAMnvcq9A1pYBVYyPeUsaRHC5OUBFOMCevNy8JwNyY
MJ0H5HQCyCysbzA1d521pogGUs/tmbE+ym9zpV8vG0b6De1PexjVeGkTNYz6NCR2
VZTQ+OJ5iE5pHPEC1Qif44LrR9Kdn/wu3RjTYyHeBOJFjK+DKgleNF4QVTcZQIPE
snN4H+/VSgTZQ3kgWbtpd1m5oRBJovEc2Qe+l+iDFCk8OA4z/x+fkvOeD3NUAl7D
9Pt3cP3UtWUJp4NJn2dvUljmQhB02HSqdNBhqKSg4/cf7l8Zo1ejvBUosrlgw3C3
apDaC4/xk7woFKVYW25teH2ze+Gpz/YsLDtmL7Bri8CGVsqsN9yqO8SstwKBa3Rt
xQ2em6XnnanApT4iFX4=
MIIE2DCCA0CgAwIBAgIUT/9u6/HtTciy3NB6UGXu+U+UzT8wDQYJKoZIhvcNAQEL
BQAwTDELMAkGA1UEBhMCREUxDTALBgNVBAoTBENTQUYxGjAYBgNVBAsTEUNTQUYg
RGlzdHJpYnV0aW9uMRIwEAYDVQQDEwljc2FmLnRlc3QwIBcNMjUxMDE3MTAyMjM1
WhgPMjEyNTA5MjMxMDIyMzVaMEwxCzAJBgNVBAYTAkRFMQ0wCwYDVQQKEwRDU0FG
MRowGAYDVQQLExFDU0FGIERpc3RyaWJ1dGlvbjESMBAGA1UEAxMJY3NhZi50ZXN0
MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwqJ45WlBG5CqW3Meewsf
Es1tqQRsHS/L6Hlz/aTZQHte/Co18qklnza0ZvK0mbPsQ8HLKXfU6Am5yw3u6vZj
XNfhWDW4QtsSk9f/y/fBADw17qYinoVyLpqZU5Z6kFRY5npY0C9bCtsAZd4qimx5
yu/MhM8LHI9K2oKPSkFgRCTRKAo9sZ97o4wZmTxJIasOr0SPpmfMLs2sHSEqcK4d
/RxZ+OtYtd3pmE/WjxtSozCkdAccvrH+TSAuF3+/6oBiov8yX0KPNEBiiwuDXMUD
QWkjfcrxQZAswMWRo55JJYBbIjrinW8vldLooFo5trNEE2nukgRPhvLhiJdKKAeg
+A8jM/Bx7JgjRCPppIEmWdvXg+CS6L0hGj49pg3OcIiNNoufoXPRkFqmRh72n1Oj
2RC13W8H3C3SDYz20mqJhkbci+05vO/LgKj9te8xEs/xa4xCtv7ycuB2Etzf1cWS
zfz5LGXwwLI0rjpx3OAsr5i8Fukxe5maYLS9AUCTetTnAgMBAAGjga8wgawwDAYD
VR0TAQH/BAIwADAnBgNVHSUEIDAeBggrBgEFBQcDAgYIKwYBBQUHAwEGCCsGAQUF
BwMJMEQGA1UdEQQ9MDuCCWNzYWYudGVzdIIJbG9jYWxob3N0ggsqLmNzYWYudGVz
dIcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0O
BBYEFN2InaQvsu6hULCYeKc6pdE4VgVHMA0GCSqGSIb3DQEBCwUAA4IBgQBjPdXd
2xHzce3mi4RlANT4nOSdpELhl54xeJDgI9Evt70N8B4uTmOI5+F6JVICE25cnDs1
c9SoHpWzh1ZuzfiBYa/cdQNUtaTfgHLi5GYtV1DzmKXVRUciBiNBWWxYMbTGvTOO
i3r6DEgOYuukeL4qj//EGOcTJEarHVSxPMuXTD/PoP/VpIdqRS9drEpFUC6lecZc
UJtUPAcyx0oD2vNmPmulDfYFMLLOPrIeNa0g7os4wgUl7+9wR1cPPRTXY0fW6Hoi
j+a8Qn80Q3PrOuEO/SZ4aHHpOk90bRqofyIhFjPwS0YN5w/Sn23uq1u2Dx+Zy+5K
6Cs9p5dJWu5/zU4ZdbQlpYIHXQVbido1TY92Z84skEsac2wVh7L2LMB3p3Gu9WYn
oKqFYCw5FICvRgyh1KG8QWhW59Em0Jxr8rTw6qyBQACdixKy6/1ok2ArMivTC8Gd
rEbefshgc6dnAZCAp1MjCU+tg9iYEymSSLdOtUKvHEIosUGO1p5ol0hReTQ=
-----END CERTIFICATE-----

View 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-----

View file

@ -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-----

View file

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

View file

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

37
internal/misc/json.go Normal file
View 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
}

View file

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

21
internal/misc/url.go Normal file
View 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
}

View file

@ -81,7 +81,7 @@ func TestUnmarshalText(t *testing.T) {
byteSlice := []byte{'3', 'h'}
var emptySlice []byte
if testTimeRange.UnmarshalText(byteSlice) != nil {
t.Errorf(testTimeRange.UnmarshalText(byteSlice).Error())
t.Error(testTimeRange.UnmarshalText(byteSlice).Error())
}
if testTimeRange.UnmarshalText(emptySlice) == nil {
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(2010, time.November, 10, 23, 0, 0, 0, time.UTC))
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 {
t.Errorf(err.Error())
t.Error(err.Error())
}
if err := testTimeRange.UnmarshalFlag("2006-01-02T15:04:05a"); err == nil {
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")
}
if err := testTimeRange.UnmarshalFlag("2006-01-02T15:04:05, 2007-01-02T15:04:05"); err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
}
}

View file

@ -46,7 +46,6 @@ type Parser[C any] struct {
// If a config file was specified it is loaded.
// Returns the arguments and the configuration.
func (p *Parser[C]) Parse() ([]string, *C, error) {
var cmdLineOpts C
if p.SetDefaults != nil {
p.SetDefaults(&cmdLineOpts)
@ -82,6 +81,7 @@ func (p *Parser[C]) Parse() ([]string, *C, error) {
// No config file -> We are good.
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
}

View file

@ -90,7 +90,7 @@ func TestParse(t *testing.T) {
cmd.Env = append(os.Environ(), "TEST_HELP=1")
err := cmd.Run()
if err != nil {
t.Fatalf(err.Error())
t.Fatal(err.Error())
}
// test the version flag
@ -104,7 +104,7 @@ func TestParse(t *testing.T) {
cmd.Env = append(os.Environ(), "TEST_VERSION=1")
err = cmd.Run()
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")
}
if err := loadTOML(&cfg, "data/config.toml"); err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
}
}

View 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

View 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"]
}
]
}
]
}

View 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"]
}
]
}
]
}

View file

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

View file

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

View file

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

View file

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

View file

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