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

Move cert handling into library and add option passphrase. Adjust uploader and checker.

This commit is contained in:
Sascha L. Teichmann 2023-08-02 21:02:58 +02:00
parent 873eb4879b
commit 017a6b0a10
5 changed files with 140 additions and 74 deletions

View file

@ -14,6 +14,7 @@ import (
"fmt"
"net/http"
"github.com/csaf-poc/csaf_distribution/v2/internal/certs"
"github.com/csaf-poc/csaf_distribution/v2/internal/filter"
"github.com/csaf-poc/csaf_distribution/v2/internal/models"
"github.com/csaf-poc/csaf_distribution/v2/internal/options"
@ -29,17 +30,18 @@ const (
type config struct {
Output string `short:"o" long:"output" description:"File name of the generated report" value-name:"REPORT-FILE" toml:"output"`
//lint:ignore SA5008 We are using choice twice: json, html.
Format outputFormat `short:"f" long:"format" choice:"json" choice:"html" description:"Format of report" toml:"format"`
Insecure bool `long:"insecure" description:"Do not check TLS certificates from provider" toml:"insecure"`
ClientCert *string `long:"client-cert" description:"TLS client certificate file (PEM encoded data)" value-name:"CERT-FILE" toml:"client_cert"`
ClientKey *string `long:"client-key" description:"TLS client private key file (PEM encoded data)" value-name:"KEY-FILE" toml:"client_key"`
Version bool `long:"version" description:"Display version of the binary" toml:"-"`
Verbose bool `long:"verbose" short:"v" description:"Verbose output" toml:"verbose"`
Rate *float64 `long:"rate" short:"r" description:"The average upper limit of https operations per second (defaults to unlimited)" toml:"rate"`
Years *uint `long:"years" short:"y" description:"Number of years to look back from now" value-name:"YEARS" toml:"years"`
Range *models.TimeRange `long:"timerange" short:"t" description:"RANGE of time from which advisories to download" value-name:"RANGE" toml:"timerange"`
IgnorePattern []string `long:"ignorepattern" short:"i" description:"Dont download files if there URLs match any of the given PATTERNs" value-name:"PATTERN" toml:"ignorepattern"`
ExtraHeader http.Header `long:"header" short:"H" description:"One or more extra HTTP header fields" toml:"header"`
Format outputFormat `short:"f" long:"format" choice:"json" choice:"html" description:"Format of report" toml:"format"`
Insecure bool `long:"insecure" description:"Do not check TLS certificates from provider" toml:"insecure"`
ClientCert *string `long:"client-cert" description:"TLS client certificate file (PEM encoded data)" value-name:"CERT-FILE" toml:"client_cert"`
ClientKey *string `long:"client-key" description:"TLS client private key file (PEM encoded data)" value-name:"KEY-FILE" toml:"client_key"`
ClientPassphrase *string `long:"client-passphrase" description:"Optional passphrase for the client certificate" value-name:"PASSPHRASE" toml:"client_passphrase"`
Version bool `long:"version" description:"Display version of the binary" toml:"-"`
Verbose bool `long:"verbose" short:"v" description:"Verbose output" toml:"verbose"`
Rate *float64 `long:"rate" short:"r" description:"The average upper limit of https operations per second (defaults to unlimited)" toml:"rate"`
Years *uint `long:"years" short:"y" description:"Number of years to look back from now" value-name:"YEARS" toml:"years"`
Range *models.TimeRange `long:"timerange" short:"t" description:"RANGE of time from which advisories to download" value-name:"RANGE" toml:"timerange"`
IgnorePattern []string `long:"ignorepattern" short:"i" description:"Dont download files if there URLs match any of the given PATTERNs" value-name:"PATTERN" toml:"ignorepattern"`
ExtraHeader http.Header `long:"header" short:"H" description:"One or more extra HTTP header fields" toml:"header"`
RemoteValidator string `long:"validator" description:"URL to validate documents remotely" value-name:"URL" toml:"validator"`
RemoteValidatorCache string `long:"validatorcache" description:"FILE to cache remote validations" value-name:"FILE" toml:"validator_cache"`
@ -139,19 +141,12 @@ func (cfg *config) compileIgnorePatterns() error {
// prepareCertificates loads the client side certificates used by the HTTP client.
func (cfg *config) prepareCertificates() error {
switch hasCert, hasKey := cfg.ClientCert != nil, cfg.ClientKey != nil; {
case hasCert && !hasKey || !hasCert && hasKey:
return errors.New("both client-key and client-cert options must be set for the authentication")
case hasCert:
cert, err := tls.LoadX509KeyPair(*cfg.ClientCert, *cfg.ClientKey)
if err != nil {
return err
}
cfg.clientCerts = []tls.Certificate{cert}
cert, err := certs.LoadCertificate(
cfg.ClientCert, cfg.ClientKey, cfg.ClientPassphrase)
if err != nil {
return err
}
cfg.clientCerts = cert
return nil
}

View file

@ -28,6 +28,7 @@ import (
"github.com/ProtonMail/gopenpgp/v2/constants"
"github.com/ProtonMail/gopenpgp/v2/crypto"
"github.com/csaf-poc/csaf_distribution/v2/csaf"
"github.com/csaf-poc/csaf_distribution/v2/internal/certs"
"github.com/csaf-poc/csaf_distribution/v2/util"
"github.com/jessevdk/go-flags"
"github.com/mitchellh/go-homedir"
@ -43,11 +44,12 @@ type options struct {
ExternalSigned bool `short:"x" long:"external-signed" description:"CSAF files are signed externally. Assumes .asc files beside CSAF files."`
NoSchemaCheck bool `short:"s" long:"no-schema-check" description:"Do not check files against CSAF JSON schema locally."`
Key *string `short:"k" long:"key" description:"OpenPGP key to sign the CSAF files" value-name:"KEY-FILE"`
Password *string `short:"p" long:"password" description:"Authentication password for accessing the CSAF provider" value-name:"PASSWORD"`
Passphrase *string `short:"P" long:"passphrase" description:"Passphrase to unlock the OpenPGP key" value-name:"PASSPHRASE"`
ClientCert *string `long:"client-cert" description:"TLS client certificate file (PEM encoded data)" value-name:"CERT-FILE.crt"`
ClientKey *string `long:"client-key" description:"TLS client private key file (PEM encoded data)" value-name:"KEY-FILE.pem"`
Key *string `short:"k" long:"key" description:"OpenPGP key to sign the CSAF files" value-name:"KEY-FILE"`
Password *string `short:"p" long:"password" description:"Authentication password for accessing the CSAF provider" value-name:"PASSWORD"`
Passphrase *string `short:"P" long:"passphrase" description:"Passphrase to unlock the OpenPGP key" value-name:"PASSPHRASE"`
ClientCert *string `long:"client-cert" description:"TLS client certificate file (PEM encoded data)" value-name:"CERT-FILE.crt"`
ClientKey *string `long:"client-key" description:"TLS client private key file (PEM encoded data)" value-name:"KEY-FILE.pem"`
ClientPassphrase *string `long:"client-passphrase" description:"Optional passphrase for the client certificate" value-name:"PASSPHRASE"`
PasswordInteractive bool `short:"i" long:"password-interactive" description:"Enter password interactively" no-ini:"true"`
PassphraseInteractive bool `short:"I" long:"passphrase-interactive" description:"Enter OpenPGP key passphrase interactively" no-ini:"true"`
@ -75,18 +77,12 @@ var iniPaths = []string{
func (o *options) prepare() error {
// Load client certs.
switch hasCert, hasKey := o.ClientCert != nil, o.ClientKey != nil; {
case hasCert && !hasKey || !hasCert && hasKey:
return errors.New("both client-key and client-cert options must be set for the authentication")
case hasCert:
cert, err := tls.LoadX509KeyPair(*o.ClientCert, *o.ClientKey)
if err != nil {
return err
}
o.clientCerts = []tls.Certificate{cert}
cert, err := certs.LoadCertificate(
o.ClientCert, o.ClientKey, o.ClientPassphrase)
if err != nil {
return err
}
o.clientCerts = cert
return nil
}